diff options
author | 2017-06-23 16:05:36 +0200 | |
---|---|---|
committer | 2017-06-26 18:31:30 +0200 | |
commit | 8880cf221e7124c0444178438d40d618e7c000ad (patch) | |
tree | 9f82d50d78c5da506241f80ee8cfc63622ccf76e /src/main/java/com/google/devtools | |
parent | c32efc8375cf482e795a43ecf4f009971722e71a (diff) |
Forbid duplicate keys in dictionary literals
RELNOTES:
When using the dictionary literal syntax, it is now an error to have
duplicated keys (e.g. {'ab': 3, 'ab': 5}).
PiperOrigin-RevId: 159945431
Diffstat (limited to 'src/main/java/com/google/devtools')
3 files changed, 34 insertions, 25 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/DictionaryLiteral.java b/src/main/java/com/google/devtools/build/lib/syntax/DictionaryLiteral.java index 87756990ae..c2328b190c 100644 --- a/src/main/java/com/google/devtools/build/lib/syntax/DictionaryLiteral.java +++ b/src/main/java/com/google/devtools/build/lib/syntax/DictionaryLiteral.java @@ -72,11 +72,12 @@ public final class DictionaryLiteral extends Expression { SkylarkDict<Object, Object> dict = SkylarkDict.<Object, Object>of(env); Location loc = getLocation(); for (DictionaryEntryLiteral entry : entries) { - if (entry == null) { - throw new EvalException(loc, "null expression in " + this); - } Object key = entry.key.eval(env); Object val = entry.value.eval(env); + if (env.getSemantics().incompatibleDictLiteralHasNoDuplicates && dict.containsKey(key)) { + throw new EvalException( + loc, "Duplicated key " + Printer.repr(key) + " when creating dictionary"); + } dict.put(key, val, loc, env); } return dict; diff --git a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkDict.java b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkDict.java index d622a7ccce..01f104bacb 100644 --- a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkDict.java +++ b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkDict.java @@ -22,29 +22,29 @@ import java.util.LinkedHashMap; import java.util.Map; import javax.annotation.Nullable; -/** - * Skylark Dict module. - */ -@SkylarkModule(name = "dict", - category = SkylarkModuleCategory.BUILTIN, - doc = "A language built-in type representating a dictionary (associative mapping). " - + "Dictionaries may be constructed with a special literal syntax:<br>" - + "<pre class=\"language-python\">d = {\"a\": 2, \"b\": 5}</pre>" - + "Use square brackets to access elements:<br>" - + "<pre class=\"language-python\">e = d[\"a\"] # e == 2</pre>" - + "Like lists, they can also be constructed using a comprehension syntax:<br>" - + "<pre class=\"language-python\">d = {i: 2*i for i in range(20)}\n" - + "e = d[8] # e == 16</pre>" - + "See also the <a href=\"globals.html#dict\">dict()</a> constructor function. " - + "<p>Iterating over a dict is equivalent to iterating over its keys. The <code>in</code> " - + "operator tests for membership in the keyset of the dict.<br>" - + "<pre class=\"language-python\">\"a\" in {\"a\" : 2, \"b\" : 5} # evaluates as True</pre>" - + "The iteration order for a dict is deterministic but not specified. When constructing a dict " - + "using any of the above methods, if there are two identical keys with conflicting values " - + "then the last value takes precedence." +/** Skylark Dict module. */ +@SkylarkModule( + name = "dict", + category = SkylarkModuleCategory.BUILTIN, + doc = + "A language built-in type representating a dictionary (associative mapping). " + + "Dictionaries may be constructed with a special literal syntax:<br>" + + "<pre class=\"language-python\">d = {\"a\": 2, \"b\": 5}</pre>" + + "When using the literal syntax, it is an error to have duplicated keys. " + + "Use square brackets to access elements:<br>" + + "<pre class=\"language-python\">e = d[\"a\"] # e == 2</pre>" + + "Like lists, they can also be constructed using a comprehension syntax:<br>" + + "<pre class=\"language-python\">d = {i: 2*i for i in range(20)}\n" + + "e = d[8] # e == 16</pre>" + + "See also the <a href=\"globals.html#dict\">dict()</a> constructor function. " + + "<p>Iterating over a dict is equivalent to iterating over its keys. The " + + "<code>in</code> operator tests for membership in the keyset of the dict.<br>" + + "<pre class=\"language-python\">\"a\" in {\"a\" : 2, \"b\" : 5} " + + "# evaluates as True</pre>" + + "The iteration order for a dict is deterministic but not specified." ) -public final class SkylarkDict<K, V> - extends MutableMap<K, V> implements Map<K, V>, SkylarkIndexable { +public final class SkylarkDict<K, V> extends MutableMap<K, V> + implements Map<K, V>, SkylarkIndexable { private final LinkedHashMap<K, V> contents = new LinkedHashMap<>(); diff --git a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkSemanticsOptions.java b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkSemanticsOptions.java index 4cca541ac8..07419e4992 100644 --- a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkSemanticsOptions.java +++ b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkSemanticsOptions.java @@ -129,4 +129,12 @@ public class SkylarkSemanticsOptions extends OptionsBase implements Serializable + "convert to a list." ) public boolean incompatibleDepsetIsNotIterable; + + @Option( + name = "incompatible_dict_literal_has_no_duplicates", + defaultValue = "false", + category = "incompatible changes", + help = "If set to true, the dictionary literal syntax doesn't allow duplicated keys." + ) + public boolean incompatibleDictLiteralHasNoDuplicates; } |