Bug 768537 part 2. Allow dictionaries to be initialized with null or undefined, and treat them as dictionaries in which everything has its default value. r=peterv

This commit is contained in:
Boris Zbarsky 2012-07-17 12:18:53 -04:00
parent 8e925299c6
commit fa17d85d47
3 changed files with 44 additions and 28 deletions

View File

@ -2058,35 +2058,30 @@ for (uint32_t i = 0; i < length; ++i) {
if type.isDictionary(): if type.isDictionary():
if failureCode is not None: if failureCode is not None:
raise TypeError("Can't handle dictionaries when failureCode is not None") raise TypeError("Can't handle dictionaries when failureCode is not None")
# There are no nullable dictionaries
assert not type.nullable()
# All optional dictionaries always have default values, so we
# should be able to assume not isOptional here.
assert not isOptional
if type.nullable(): typeName = CGDictionary.makeDictionaryName(type.inner,
typeName = CGDictionary.makeDictionaryName(type.inner.inner, descriptorProvider.workers)
descriptorProvider.workers) actualTypeName = typeName
actualTypeName = "Nullable<%s>" % typeName selfRef = "${declName}"
selfRef = "const_cast<%s&>(${declName}).SetValue()" % actualTypeName
else:
typeName = CGDictionary.makeDictionaryName(type.inner,
descriptorProvider.workers)
actualTypeName = typeName
selfRef = "${declName}"
declType = CGGeneric(actualTypeName) declType = CGGeneric(actualTypeName)
# If we're optional or a member of something else, the const # If we're a member of something else, the const
# will come from the Optional or our container. # will come from the Optional or our container.
if not isOptional and not isMember: if not isMember:
declType = CGWrapper(declType, pre="const ") declType = CGWrapper(declType, pre="const ")
selfRef = "const_cast<%s&>(%s)" % (typeName, selfRef) selfRef = "const_cast<%s&>(%s)" % (typeName, selfRef)
template = wrapObjectTemplate("if (!%s.Init(cx, &${val}.toObject())) {\n" template = ("if (!%s.Init(cx, ${val})) {\n"
" return false;\n" " return false;\n"
"}" % selfRef, "}" % selfRef)
isDefinitelyObject, type,
("const_cast<%s&>(${declName}).SetNull()" %
actualTypeName),
descriptorProvider.workers, None)
return (template, declType, None, isOptional) return (template, declType, None, False)
if not type.isPrimitive(): if not type.isPrimitive():
raise TypeError("Need conversion for argument type '%s'" % type) raise TypeError("Need conversion for argument type '%s'" % type)
@ -2833,6 +2828,13 @@ class CGMethodCall(CGThing):
distinguishingIndex = method.distinguishingIndexForArgCount(argCount) distinguishingIndex = method.distinguishingIndexForArgCount(argCount)
# We can't handle unions at the distinguishing index.
for (returnType, args) in possibleSignatures:
if args[distinguishingIndex].type.isUnion():
raise TypeError("No support for unions as distinguishing "
"arguments yet: %s",
args[distinguishingIndex].location)
# Convert all our arguments up to the distinguishing index. # Convert all our arguments up to the distinguishing index.
# Doesn't matter which of the possible signatures we use, since # Doesn't matter which of the possible signatures we use, since
# they all have the same types up to that point; just use # they all have the same types up to that point; just use
@ -2863,7 +2865,8 @@ class CGMethodCall(CGThing):
# First check for null or undefined # First check for null or undefined
pickFirstSignature("%s.isNullOrUndefined()" % distinguishingArg, pickFirstSignature("%s.isNullOrUndefined()" % distinguishingArg,
lambda s: s[1][distinguishingIndex].type.nullable()) lambda s: (s[1][distinguishingIndex].type.nullable() or
s[1][distinguishingIndex].type.isDictionary()))
# Now check for distinguishingArg being an object that implements a # Now check for distinguishingArg being an object that implements a
# non-callback interface. That includes typed arrays and # non-callback interface. That includes typed arrays and
@ -3282,6 +3285,8 @@ def getUnionAccessorSignatureType(type, descriptorProvider):
def getUnionTypeTemplateVars(type, descriptorProvider): def getUnionTypeTemplateVars(type, descriptorProvider):
# For dictionaries and sequences we need to pass None as the failureCode # For dictionaries and sequences we need to pass None as the failureCode
# for getJSToNativeConversionTemplate. # for getJSToNativeConversionTemplate.
# Also, for dictionaries we would need to handle conversion of
# null/undefined to the dictionary correctly.
if type.isDictionary() or type.isSequence(): if type.isDictionary() or type.isSequence():
raise TypeError("Can't handle dictionaries or sequences in unions") raise TypeError("Can't handle dictionaries or sequences in unions")
@ -4106,7 +4111,7 @@ class CGDictionary(CGThing):
return (string.Template( return (string.Template(
"struct ${selfName} ${inheritance}{\n" "struct ${selfName} ${inheritance}{\n"
" ${selfName}() {}\n" " ${selfName}() {}\n"
" bool Init(JSContext* cx, JSObject* obj);\n" " bool Init(JSContext* cx, const JS::Value& val);\n"
"\n" + "\n" +
"\n".join(memberDecls) + "\n" "\n".join(memberDecls) + "\n"
"private:\n" "private:\n"
@ -4126,7 +4131,7 @@ class CGDictionary(CGThing):
d = self.dictionary d = self.dictionary
if d.parent: if d.parent:
initParent = ("// Per spec, we init the parent's members first\n" initParent = ("// Per spec, we init the parent's members first\n"
"if (!%s::Init(cx, obj)) {\n" "if (!%s::Init(cx, val)) {\n"
" return false;\n" " return false;\n"
"}\n" % self.makeClassName(d.parent)) "}\n" % self.makeClassName(d.parent))
else: else:
@ -4160,7 +4165,7 @@ class CGDictionary(CGThing):
"}\n" "}\n"
"\n" "\n"
"bool\n" "bool\n"
"${selfName}::Init(JSContext* cx, JSObject* obj)\n" "${selfName}::Init(JSContext* cx, const JS::Value& val)\n"
"{\n" "{\n"
" if (!initedIds && !InitIds(cx)) {\n" " if (!initedIds && !InitIds(cx)) {\n"
" return false;\n" " return false;\n"
@ -4168,6 +4173,10 @@ class CGDictionary(CGThing):
"${initParent}" "${initParent}"
" JSBool found;\n" " JSBool found;\n"
" JS::Value temp;\n" " JS::Value temp;\n"
" bool isNull = val.isNullOrUndefined();\n"
" if (!isNull && !val.isObject()) {\n"
" return Throw<${isMainThread}>(cx, NS_ERROR_XPC_BAD_CONVERT_JS);\n"
" }\n"
"\n" "\n"
"${initMembers}\n" "${initMembers}\n"
" return true;\n" " return true;\n"
@ -4175,7 +4184,8 @@ class CGDictionary(CGThing):
"selfName": self.makeClassName(d), "selfName": self.makeClassName(d),
"initParent": CGIndenter(CGGeneric(initParent)).define(), "initParent": CGIndenter(CGGeneric(initParent)).define(),
"initMembers": "\n\n".join(memberInits), "initMembers": "\n\n".join(memberInits),
"idInit": CGIndenter(idinit).define() "idInit": CGIndenter(idinit).define(),
"isMainThread": toStringBool(not self.workers)
}) })
@staticmethod @staticmethod
@ -4222,13 +4232,15 @@ class CGDictionary(CGThing):
"prop": "(this->%s)" % member.identifier.name, "prop": "(this->%s)" % member.identifier.name,
"convert": string.Template(templateBody).substitute(replacements) "convert": string.Template(templateBody).substitute(replacements)
} }
conversion = ("if (!JS_HasPropertyById(cx, obj, ${propId}, &found)) {\n" conversion = ("if (isNull) {\n"
" found = false;\n"
"} else if (!JS_HasPropertyById(cx, &val.toObject(), ${propId}, &found)) {\n"
" return false;\n" " return false;\n"
"}\n") "}\n")
if member.defaultValue: if member.defaultValue:
conversion += ( conversion += (
"if (found) {\n" "if (found) {\n"
" if (!JS_GetPropertyById(cx, obj, ${propId}, &temp)) {\n" " if (!JS_GetPropertyById(cx, &val.toObject(), ${propId}, &temp)) {\n"
" return false;\n" " return false;\n"
" }\n" " }\n"
"} else {\n" "} else {\n"
@ -4241,7 +4253,7 @@ class CGDictionary(CGThing):
conversion += ( conversion += (
"if (found) {\n" "if (found) {\n"
" ${prop}.Construct();\n" " ${prop}.Construct();\n"
" if (!JS_GetPropertyById(cx, obj, ${propId}, &temp)) {\n" " if (!JS_GetPropertyById(cx, &val.toObject(), ${propId}, &temp)) {\n"
" return false;\n" " return false;\n"
" }\n" " }\n"
"${convert}\n" "${convert}\n"

View File

@ -348,6 +348,8 @@ public:
void PassDictionary(const Dict&, ErrorResult&); void PassDictionary(const Dict&, ErrorResult&);
void PassOtherDictionary(const GrandparentDict&, ErrorResult&); void PassOtherDictionary(const GrandparentDict&, ErrorResult&);
void PassSequenceOfDictionaries(const Sequence<Dict>&, ErrorResult&); void PassSequenceOfDictionaries(const Sequence<Dict>&, ErrorResult&);
void PassDictionaryOrLong(const Dict&, ErrorResult&);
void PassDictionaryOrLong(int32_t, ErrorResult&);
// Methods and properties imported via "implements" // Methods and properties imported via "implements"
bool GetImplementedProperty(ErrorResult&); bool GetImplementedProperty(ErrorResult&);

View File

@ -264,6 +264,8 @@ interface TestInterface {
void passDictionary(optional Dict x); void passDictionary(optional Dict x);
void passOtherDictionary(optional GrandparentDict x); void passOtherDictionary(optional GrandparentDict x);
void passSequenceOfDictionaries(sequence<Dict> x); void passSequenceOfDictionaries(sequence<Dict> x);
void passDictionaryOrLong(optional Dict x);
void passDictionaryOrLong(long x);
}; };
interface TestNonWrapperCacheInterface { interface TestNonWrapperCacheInterface {