Chromium Code Reviews| Index: sdk/lib/_internal/compiler/implementation/ssa/builder.dart |
| diff --git a/sdk/lib/_internal/compiler/implementation/ssa/builder.dart b/sdk/lib/_internal/compiler/implementation/ssa/builder.dart |
| index c3b9ed91b625bcab9a7ee11f1a4b0fa465fe3dc9..c682305f0a2bcba41e93d8e6c15f2014e96dce49 100644 |
| --- a/sdk/lib/_internal/compiler/implementation/ssa/builder.dart |
| +++ b/sdk/lib/_internal/compiler/implementation/ssa/builder.dart |
| @@ -1921,6 +1921,22 @@ class SsaBuilder extends ResolvedVisitor implements Visitor { |
| return other; |
| } |
| + void assertIsSubtype(Node node, DartType subtype, DartType supertype, |
| + String message) { |
| + HInstruction subtypeInstruction = analyzeTypeArgument(subtype); |
| + HInstruction supertypeInstruction = analyzeTypeArgument(supertype); |
| + HInstruction messageInstruction = |
| + graph.addConstantString(new DartString.literal(message), |
| + node, compiler); |
| + Element element = backend.getAssertIsSubtype(); |
| + var inputs = <HInstruction>[subtypeInstruction, supertypeInstruction, |
| + messageInstruction]; |
| + HInstruction assertIsSubtype = new HInvokeStatic( |
| + element, inputs, subtypeInstruction.instructionType); |
| + compiler.backend.registerTypeVariableBoundsSubtypeCheck(subtype, supertype); |
| + add(assertIsSubtype); |
| + } |
| + |
| HGraph closeFunction() { |
| // TODO(kasperl): Make this goto an implicit return. |
| if (!isAborted()) closeAndGotoExit(new HGoto()); |
| @@ -3645,6 +3661,8 @@ class SsaBuilder extends ResolvedVisitor implements Visitor { |
| type = functionElement.computeTargetType(compiler, type); |
| } |
| + if (checkTypeVariableBounds(node, type)) return; |
| + |
| var inputs = <HInstruction>[]; |
| if (constructor.isGenerativeConstructor() && |
| Elements.isNativeOrExtendsNative(constructor.getEnclosingClass())) { |
| @@ -3702,6 +3720,66 @@ class SsaBuilder extends ResolvedVisitor implements Visitor { |
| } |
| } |
| + /// In checked mode checks the [type] of [node] to be well-bounded. The method |
| + /// returns [:true:] if an error can be statically determined. |
| + bool checkTypeVariableBounds(NewExpression node, InterfaceType type) { |
| + if (!compiler.enableTypeAssertions) return false; |
| + |
| + Map<DartType, Set<DartType>> seenChecksMap = |
| + new Map<DartType, Set<DartType>>(); |
| + bool staticError = false; |
|
karlklose
2013/10/30 09:47:43
How about 'definitelyFails'?
Johnni Winther
2013/10/30 11:19:42
Done.
|
| + |
| + addTypeVariableBoundCheck(GenericType instance, |
| + DartType typeArgument, |
| + TypeVariableType typeVariable, |
| + DartType bound) { |
| + if (staticError) return; |
| + |
| + int maybeSubtype = compiler.types.isMaybeSubtype(typeArgument, bound); |
|
karlklose
2013/10/30 09:47:43
'maybeSubtype' -> 'subtypeRelation'?
Johnni Winther
2013/10/30 11:19:42
Done.
|
| + if (maybeSubtype == Types.IS_SUBTYPE) return; |
| + |
| + String message; |
|
karlklose
2013/10/30 09:47:43
You can merge the two branches like this:
String
Johnni Winther
2013/10/30 11:19:42
Done.
|
| + if (type == instance) { |
| + message = "Can't create an instance of malbounded type '$type': " |
| + "'${typeArgument}' is not a subtype of bound '${bound}' for " |
| + "type variable '${typeVariable}' of type " |
| + "'${type.element.thisType}'."; |
| + } else { |
| + message = "Can't create an instance of malbounded type '$type': " |
| + "'${typeArgument}' is not a subtype of bound '${bound}' for " |
| + "type variable '${typeVariable}' of type " |
| + "'${instance.element.thisType}' on the supertype '${instance}' of " |
| + "'${type}'."; |
| + } |
| + if (maybeSubtype == Types.NOT_SUBTYPE) { |
| + generateTypeError(node, message); |
| + staticError = true; |
| + return; |
| + } else if (maybeSubtype == Types.MAYBE_SUBTYPE) { |
| + Set<DartType> seenChecks = |
| + seenChecksMap.putIfAbsent(typeArgument, () => new Set<DartType>()); |
| + if (!seenChecks.contains(bound)) { |
| + seenChecks.add(bound); |
| + assertIsSubtype(node, typeArgument, bound, message); |
| + } |
| + } |
| + } |
| + |
| + compiler.types.checkTypeVariableBounds(type, addTypeVariableBoundCheck); |
| + if (staticError) { |
| + return true; |
| + } |
| + for (InterfaceType supertype in type.element.allSupertypes) { |
| + DartType instance = type.asInstanceOf(supertype.element); |
| + compiler.types.checkTypeVariableBounds(instance, |
| + addTypeVariableBoundCheck); |
| + if (staticError) { |
| + return true; |
| + } |
| + } |
| + return false; |
| + } |
| + |
| visitAssert(node) { |
| if (!compiler.enableUserAssertions) { |
| stack.add(graph.addConstantNull(compiler)); |
| @@ -3814,6 +3892,10 @@ class SsaBuilder extends ResolvedVisitor implements Visitor { |
| generateError(node, message, backend.getThrowRuntimeError()); |
| } |
| + void generateTypeError(Node node, String message) { |
| + generateError(node, message, backend.getThrowTypeError()); |
| + } |
| + |
| void generateAbstractClassInstantiationError(Node node, String message) { |
| generateError(node, |
| message, |