| Index: lib/compiler/implementation/typechecker.dart
|
| diff --git a/lib/compiler/implementation/typechecker.dart b/lib/compiler/implementation/typechecker.dart
|
| index 1ac592b557d0c985ad4d34f88fe7e73a30751c5a..fc82c88311e9514d7b9eadbbafb61a800efa1a99 100644
|
| --- a/lib/compiler/implementation/typechecker.dart
|
| +++ b/lib/compiler/implementation/typechecker.dart
|
| @@ -24,7 +24,7 @@ class TypeCheckerTask extends CompilerTask {
|
| }
|
| }
|
|
|
| -interface Type {
|
| +interface DartType {
|
| SourceString get name();
|
| Element get element();
|
|
|
| @@ -38,17 +38,17 @@ interface Type {
|
| * function type [: (B) -> A :] and the unaliased type of
|
| * [: Func<int,String> :] is the function type [: (String) -> int :].
|
| */
|
| - Type unalias(Compiler compiler);
|
| + DartType unalias(Compiler compiler);
|
| }
|
|
|
| -class TypeVariableType implements Type {
|
| +class TypeVariableType implements DartType {
|
| final TypeVariableElement element;
|
|
|
| TypeVariableType(this.element);
|
|
|
| SourceString get name => element.name;
|
|
|
| - Type unalias(Compiler compiler) => this;
|
| + DartType unalias(Compiler compiler) => this;
|
|
|
| String toString() => name.slowToString();
|
| }
|
| @@ -56,7 +56,7 @@ class TypeVariableType implements Type {
|
| /**
|
| * A statement type tracks whether a statement returns or may return.
|
| */
|
| -class StatementType implements Type {
|
| +class StatementType implements DartType {
|
| final String stringName;
|
| Element get element => null;
|
|
|
| @@ -73,31 +73,31 @@ class StatementType implements Type {
|
| return (this === other) ? this : MAYBE_RETURNING;
|
| }
|
|
|
| - Type unalias(Compiler compiler) => this;
|
| + DartType unalias(Compiler compiler) => this;
|
|
|
| String toString() => stringName;
|
| }
|
|
|
| -class VoidType implements Type {
|
| +class VoidType implements DartType {
|
| const VoidType(this.element);
|
| SourceString get name => element.name;
|
| final VoidElement element;
|
|
|
| - Type unalias(Compiler compiler) => this;
|
| + DartType unalias(Compiler compiler) => this;
|
|
|
| String toString() => name.slowToString();
|
| }
|
|
|
| -class InterfaceType implements Type {
|
| +class InterfaceType implements DartType {
|
| final Element element;
|
| - final Link<Type> arguments;
|
| + final Link<DartType> arguments;
|
|
|
| const InterfaceType(this.element,
|
| - [this.arguments = const EmptyLink<Type>()]);
|
| + [this.arguments = const EmptyLink<DartType>()]);
|
|
|
| SourceString get name => element.name;
|
|
|
| - Type unalias(Compiler compiler) => this;
|
| + DartType unalias(Compiler compiler) => this;
|
|
|
| String toString() {
|
| StringBuffer sb = new StringBuffer();
|
| @@ -111,15 +111,15 @@ class InterfaceType implements Type {
|
| }
|
| }
|
|
|
| -class FunctionType implements Type {
|
| +class FunctionType implements DartType {
|
| final Element element;
|
| - Type returnType;
|
| - Link<Type> parameterTypes;
|
| + DartType returnType;
|
| + Link<DartType> parameterTypes;
|
|
|
| - FunctionType(Type this.returnType, Link<Type> this.parameterTypes,
|
| + FunctionType(DartType this.returnType, Link<DartType> this.parameterTypes,
|
| Element this.element);
|
|
|
| - Type unalias(Compiler compiler) => this;
|
| + DartType unalias(Compiler compiler) => this;
|
|
|
| String toString() {
|
| StringBuffer sb = new StringBuffer();
|
| @@ -146,16 +146,16 @@ class FunctionType implements Type {
|
| }
|
| }
|
|
|
| -class TypedefType implements Type {
|
| +class TypedefType implements DartType {
|
| final TypedefElement element;
|
| - final Link<Type> typeArguments;
|
| + final Link<DartType> typeArguments;
|
|
|
| const TypedefType(this.element,
|
| - [this.typeArguments = const EmptyLink<Type>()]);
|
| + [this.typeArguments = const EmptyLink<DartType>()]);
|
|
|
| SourceString get name => element.name;
|
|
|
| - Type unalias(Compiler compiler) {
|
| + DartType unalias(Compiler compiler) {
|
| // TODO(ahe): This should be [ensureResolved].
|
| compiler.resolveTypedef(element);
|
| return element.alias.unalias(compiler);
|
| @@ -190,7 +190,7 @@ class Types {
|
| dynamicType = new InterfaceType(dynamicElement);
|
|
|
| /** Returns true if t is a subtype of s */
|
| - bool isSubtype(Type t, Type s) {
|
| + bool isSubtype(DartType t, DartType s) {
|
| if (t === s ||
|
| t === dynamicType ||
|
| s === dynamicType ||
|
| @@ -206,10 +206,10 @@ class Types {
|
| if (s is !InterfaceType) return false;
|
| ClassElement tc = t.element;
|
| if (tc === s.element) return true;
|
| - for (Link<Type> supertypes = tc.allSupertypes;
|
| + for (Link<DartType> supertypes = tc.allSupertypes;
|
| supertypes != null && !supertypes.isEmpty();
|
| supertypes = supertypes.tail) {
|
| - Type supertype = supertypes.head;
|
| + DartType supertype = supertypes.head;
|
| if (supertype.element === s.element) return true;
|
| }
|
| return false;
|
| @@ -218,8 +218,8 @@ class Types {
|
| if (s is !FunctionType) return false;
|
| FunctionType tf = t;
|
| FunctionType sf = s;
|
| - Link<Type> tps = tf.parameterTypes;
|
| - Link<Type> sps = sf.parameterTypes;
|
| + Link<DartType> tps = tf.parameterTypes;
|
| + Link<DartType> sps = sf.parameterTypes;
|
| while (!tps.isEmpty() && !sps.isEmpty()) {
|
| if (!isAssignable(tps.head, sps.head)) return false;
|
| tps = tps.tail;
|
| @@ -236,7 +236,7 @@ class Types {
|
| }
|
| }
|
|
|
| - bool isAssignable(Type r, Type s) {
|
| + bool isAssignable(DartType r, DartType s) {
|
| return isSubtype(r, s) || isSubtype(s, r);
|
| }
|
| }
|
| @@ -248,23 +248,23 @@ class CancelTypeCheckException {
|
| CancelTypeCheckException(this.node, this.reason);
|
| }
|
|
|
| -class TypeCheckerVisitor implements Visitor<Type> {
|
| +class TypeCheckerVisitor implements Visitor<DartType> {
|
| final Compiler compiler;
|
| final TreeElements elements;
|
| final Types types;
|
|
|
| Node lastSeenNode;
|
| - Type expectedReturnType;
|
| + DartType expectedReturnType;
|
| ClassElement currentClass;
|
|
|
| - Link<Type> cascadeTypes = const EmptyLink<Type>();
|
| + Link<DartType> cascadeTypes = const EmptyLink<DartType>();
|
|
|
| - Type intType;
|
| - Type doubleType;
|
| - Type boolType;
|
| - Type stringType;
|
| - Type objectType;
|
| - Type listType;
|
| + DartType intType;
|
| + DartType doubleType;
|
| + DartType boolType;
|
| + DartType stringType;
|
| + DartType objectType;
|
| + DartType listType;
|
|
|
| TypeCheckerVisitor(this.compiler, this.elements, this.types) {
|
| intType = compiler.intClass.computeType(compiler);
|
| @@ -275,7 +275,7 @@ class TypeCheckerVisitor implements Visitor<Type> {
|
| listType = compiler.listClass.computeType(compiler);
|
| }
|
|
|
| - Type fail(node, [reason]) {
|
| + DartType fail(node, [reason]) {
|
| String message = 'cannot type-check';
|
| if (reason !== null) {
|
| message = '$message: $reason';
|
| @@ -288,22 +288,22 @@ class TypeCheckerVisitor implements Visitor<Type> {
|
| }
|
|
|
| // TODO(karlklose): remove these functions.
|
| - Type unhandledStatement() => StatementType.NOT_RETURNING;
|
| - Type unhandledExpression() => types.dynamicType;
|
| + DartType unhandledStatement() => StatementType.NOT_RETURNING;
|
| + DartType unhandledExpression() => types.dynamicType;
|
|
|
| - Type analyzeNonVoid(Node node) {
|
| - Type type = analyze(node);
|
| + DartType analyzeNonVoid(Node node) {
|
| + DartType type = analyze(node);
|
| if (type == types.voidType) {
|
| reportTypeWarning(node, MessageKind.VOID_EXPRESSION);
|
| }
|
| return type;
|
| }
|
|
|
| - Type analyzeWithDefault(Node node, Type defaultValue) {
|
| + DartType analyzeWithDefault(Node node, DartType defaultValue) {
|
| return node !== null ? analyze(node) : defaultValue;
|
| }
|
|
|
| - Type analyze(Node node) {
|
| + DartType analyze(Node node) {
|
| if (node == null) {
|
| final String error = 'internal error: unexpected node: null';
|
| if (lastSeenNode != null) {
|
| @@ -314,7 +314,7 @@ class TypeCheckerVisitor implements Visitor<Type> {
|
| } else {
|
| lastSeenNode = node;
|
| }
|
| - Type result = node.accept(this);
|
| + DartType result = node.accept(this);
|
| // TODO(karlklose): record type?
|
| if (result === null) {
|
| fail(node, 'internal error: type is null');
|
| @@ -326,7 +326,7 @@ class TypeCheckerVisitor implements Visitor<Type> {
|
| * Check if a value of type t can be assigned to a variable,
|
| * parameter or return value of type s.
|
| */
|
| - checkAssignable(Node node, Type s, Type t) {
|
| + checkAssignable(Node node, DartType s, DartType t) {
|
| if (!types.isAssignable(s, t)) {
|
| reportTypeWarning(node, MessageKind.NOT_ASSIGNABLE, [s, t]);
|
| }
|
| @@ -336,48 +336,48 @@ class TypeCheckerVisitor implements Visitor<Type> {
|
| checkAssignable(condition, boolType, analyze(condition));
|
| }
|
|
|
| - void pushCascadeType(Type type) {
|
| + void pushCascadeType(DartType type) {
|
| cascadeTypes = cascadeTypes.prepend(type);
|
| }
|
|
|
| - Type popCascadeType() {
|
| - Type type = cascadeTypes.head;
|
| + DartType popCascadeType() {
|
| + DartType type = cascadeTypes.head;
|
| cascadeTypes = cascadeTypes.tail;
|
| return type;
|
| }
|
|
|
| - Type visitBlock(Block node) {
|
| + DartType visitBlock(Block node) {
|
| return analyze(node.statements);
|
| }
|
|
|
| - Type visitCascade(Cascade node) {
|
| + DartType visitCascade(Cascade node) {
|
| analyze(node.expression);
|
| return popCascadeType();
|
| }
|
|
|
| - Type visitCascadeReceiver(CascadeReceiver node) {
|
| - Type type = analyze(node.expression);
|
| + DartType visitCascadeReceiver(CascadeReceiver node) {
|
| + DartType type = analyze(node.expression);
|
| pushCascadeType(type);
|
| return type;
|
| }
|
|
|
| - Type visitClassNode(ClassNode node) {
|
| + DartType visitClassNode(ClassNode node) {
|
| fail(node);
|
| }
|
|
|
| - Type visitDoWhile(DoWhile node) {
|
| + DartType visitDoWhile(DoWhile node) {
|
| StatementType bodyType = analyze(node.body);
|
| checkCondition(node.condition);
|
| return bodyType.join(StatementType.NOT_RETURNING);
|
| }
|
|
|
| - Type visitExpressionStatement(ExpressionStatement node) {
|
| + DartType visitExpressionStatement(ExpressionStatement node) {
|
| analyze(node.expression);
|
| return StatementType.NOT_RETURNING;
|
| }
|
|
|
| /** Dart Programming Language Specification: 11.5.1 For Loop */
|
| - Type visitFor(For node) {
|
| + DartType visitFor(For node) {
|
| analyzeWithDefault(node.initializer, StatementType.NOT_RETURNING);
|
| checkCondition(node.condition);
|
| analyzeWithDefault(node.update, StatementType.NOT_RETURNING);
|
| @@ -385,15 +385,15 @@ class TypeCheckerVisitor implements Visitor<Type> {
|
| return bodyType.join(StatementType.NOT_RETURNING);
|
| }
|
|
|
| - Type visitFunctionDeclaration(FunctionDeclaration node) {
|
| + DartType visitFunctionDeclaration(FunctionDeclaration node) {
|
| analyze(node.function);
|
| return StatementType.NOT_RETURNING;
|
| }
|
|
|
| - Type visitFunctionExpression(FunctionExpression node) {
|
| - Type type;
|
| - Type returnType;
|
| - Type previousType;
|
| + DartType visitFunctionExpression(FunctionExpression node) {
|
| + DartType type;
|
| + DartType returnType;
|
| + DartType previousType;
|
| final FunctionElement element = elements[node];
|
| if (Element.isInvalid(element)) return types.dynamicType;
|
| if (element.kind === ElementKind.GENERATIVE_CONSTRUCTOR ||
|
| @@ -405,7 +405,7 @@ class TypeCheckerVisitor implements Visitor<Type> {
|
| returnType = functionType.returnType;
|
| type = functionType;
|
| }
|
| - Type previous = expectedReturnType;
|
| + DartType previous = expectedReturnType;
|
| expectedReturnType = returnType;
|
| if (element.isMember()) currentClass = element.getEnclosingClass();
|
| StatementType bodyType = analyze(node.body);
|
| @@ -423,7 +423,7 @@ class TypeCheckerVisitor implements Visitor<Type> {
|
| return type;
|
| }
|
|
|
| - Type visitIdentifier(Identifier node) {
|
| + DartType visitIdentifier(Identifier node) {
|
| if (node.isThis()) {
|
| return currentClass.computeType(compiler);
|
| } else {
|
| @@ -432,7 +432,7 @@ class TypeCheckerVisitor implements Visitor<Type> {
|
| }
|
| }
|
|
|
| - Type visitIf(If node) {
|
| + DartType visitIf(If node) {
|
| checkCondition(node.condition);
|
| StatementType thenType = analyze(node.thenPart);
|
| StatementType elseType = node.hasElsePart ? analyze(node.elsePart)
|
| @@ -440,16 +440,16 @@ class TypeCheckerVisitor implements Visitor<Type> {
|
| return thenType.join(elseType);
|
| }
|
|
|
| - Type visitLoop(Loop node) {
|
| + DartType visitLoop(Loop node) {
|
| return unhandledStatement();
|
| }
|
|
|
| - Type lookupMethodType(Node node, ClassElement classElement,
|
| + DartType lookupMethodType(Node node, ClassElement classElement,
|
| SourceString name) {
|
| Element member = classElement.lookupLocalMember(name);
|
| if (member === null) {
|
| classElement.ensureResolved(compiler);
|
| - for (Link<Type> supertypes = classElement.allSupertypes;
|
| + for (Link<DartType> supertypes = classElement.allSupertypes;
|
| !supertypes.isEmpty() && member === null;
|
| supertypes = supertypes.tail) {
|
| ClassElement lookupTarget = supertypes.head.element;
|
| @@ -464,7 +464,7 @@ class TypeCheckerVisitor implements Visitor<Type> {
|
| return types.dynamicType;
|
| }
|
|
|
| - void analyzeArguments(Send send, Type type) {
|
| + void analyzeArguments(Send send, DartType type) {
|
| Link<Node> arguments = send.arguments;
|
| if (type === null || type === types.dynamicType) {
|
| while(!arguments.isEmpty()) {
|
| @@ -473,7 +473,7 @@ class TypeCheckerVisitor implements Visitor<Type> {
|
| }
|
| } else {
|
| FunctionType funType = type;
|
| - Link<Type> parameterTypes = funType.parameterTypes;
|
| + Link<DartType> parameterTypes = funType.parameterTypes;
|
| while (!arguments.isEmpty() && !parameterTypes.isEmpty()) {
|
| checkAssignable(arguments.head, parameterTypes.head,
|
| analyze(arguments.head));
|
| @@ -489,7 +489,7 @@ class TypeCheckerVisitor implements Visitor<Type> {
|
| }
|
| }
|
|
|
| - Type visitSend(Send node) {
|
| + DartType visitSend(Send node) {
|
| Element element = elements[node];
|
|
|
| if (Elements.isClosureSend(node, element)) {
|
| @@ -505,10 +505,11 @@ class TypeCheckerVisitor implements Visitor<Type> {
|
| return boolType;
|
| } else if (node.isOperator) {
|
| final Node firstArgument = node.receiver;
|
| - final Type firstArgumentType = analyze(node.receiver);
|
| + final DartType firstArgumentType = analyze(node.receiver);
|
| final arguments = node.arguments;
|
| final Node secondArgument = arguments.isEmpty() ? null : arguments.head;
|
| - final Type secondArgumentType = analyzeWithDefault(secondArgument, null);
|
| + final DartType secondArgumentType =
|
| + analyzeWithDefault(secondArgument, null);
|
|
|
| if (name === '+' || name === '=' || name === '-'
|
| || name === '*' || name === '/' || name === '%'
|
| @@ -544,7 +545,7 @@ class TypeCheckerVisitor implements Visitor<Type> {
|
| } else {
|
| FunctionType computeFunType() {
|
| if (node.receiver !== null) {
|
| - Type receiverType = analyze(node.receiver);
|
| + DartType receiverType = analyze(node.receiver);
|
| if (receiverType.element == compiler.dynamicClass) return null;
|
| if (receiverType === null) {
|
| fail(node.receiver, 'receivertype is null');
|
| @@ -567,7 +568,7 @@ class TypeCheckerVisitor implements Visitor<Type> {
|
| }
|
| ClassElement classElement = receiverType.element;
|
| // TODO(karlklose): substitute type arguments.
|
| - Type memberType =
|
| + DartType memberType =
|
| lookupMethodType(selector, classElement, selector.source);
|
| if (memberType.element === compiler.dynamicClass) return null;
|
| return memberType;
|
| @@ -598,58 +599,58 @@ class TypeCheckerVisitor implements Visitor<Type> {
|
| final name = node.assignmentOperator.source.stringValue;
|
| if (name === '++' || name === '--') {
|
| final Element element = elements[node.selector];
|
| - final Type receiverType = computeType(element);
|
| + final DartType receiverType = computeType(element);
|
| // TODO(karlklose): this should be the return type instead of int.
|
| return node.isPrefix ? intType : receiverType;
|
| } else {
|
| - Type targetType = computeType(elements[node]);
|
| + DartType targetType = computeType(elements[node]);
|
| Node value = node.arguments.head;
|
| checkAssignable(value, targetType, analyze(value));
|
| return targetType;
|
| }
|
| }
|
|
|
| - Type visitLiteralInt(LiteralInt node) {
|
| + DartType visitLiteralInt(LiteralInt node) {
|
| return intType;
|
| }
|
|
|
| - Type visitLiteralDouble(LiteralDouble node) {
|
| + DartType visitLiteralDouble(LiteralDouble node) {
|
| return doubleType;
|
| }
|
|
|
| - Type visitLiteralBool(LiteralBool node) {
|
| + DartType visitLiteralBool(LiteralBool node) {
|
| return boolType;
|
| }
|
|
|
| - Type visitLiteralString(LiteralString node) {
|
| + DartType visitLiteralString(LiteralString node) {
|
| return stringType;
|
| }
|
|
|
| - Type visitStringJuxtaposition(StringJuxtaposition node) {
|
| + DartType visitStringJuxtaposition(StringJuxtaposition node) {
|
| analyze(node.first);
|
| analyze(node.second);
|
| return stringType;
|
| }
|
|
|
| - Type visitLiteralNull(LiteralNull node) {
|
| + DartType visitLiteralNull(LiteralNull node) {
|
| return types.dynamicType;
|
| }
|
|
|
| - Type visitNewExpression(NewExpression node) {
|
| + DartType visitNewExpression(NewExpression node) {
|
| Element element = elements[node.send];
|
| analyzeArguments(node.send, computeType(element));
|
| return analyze(node.send.selector);
|
| }
|
|
|
| - Type visitLiteralList(LiteralList node) {
|
| + DartType visitLiteralList(LiteralList node) {
|
| return listType;
|
| }
|
|
|
| - Type visitNodeList(NodeList node) {
|
| - Type type = StatementType.NOT_RETURNING;
|
| + DartType visitNodeList(NodeList node) {
|
| + DartType type = StatementType.NOT_RETURNING;
|
| bool reportedDeadCode = false;
|
| for (Link<Node> link = node.nodes; !link.isEmpty(); link = link.tail) {
|
| - Type nextType = analyze(link.head);
|
| + DartType nextType = analyze(link.head);
|
| if (type == StatementType.RETURNING) {
|
| if (!reportedDeadCode) {
|
| reportTypeWarning(link.head, MessageKind.UNREACHABLE_CODE);
|
| @@ -666,12 +667,12 @@ class TypeCheckerVisitor implements Visitor<Type> {
|
| return type;
|
| }
|
|
|
| - Type visitOperator(Operator node) {
|
| + DartType visitOperator(Operator node) {
|
| fail(node, 'internal error');
|
| }
|
|
|
| /** Dart Programming Language Specification: 11.10 Return */
|
| - Type visitReturn(Return node) {
|
| + DartType visitReturn(Return node) {
|
| if (node.getBeginToken().stringValue === 'native') {
|
| return StatementType.RETURNING;
|
| }
|
| @@ -703,18 +704,18 @@ class TypeCheckerVisitor implements Visitor<Type> {
|
| return StatementType.RETURNING;
|
| }
|
|
|
| - Type visitThrow(Throw node) {
|
| + DartType visitThrow(Throw node) {
|
| if (node.expression !== null) analyze(node.expression);
|
| return StatementType.RETURNING;
|
| }
|
|
|
| - Type computeType(Element element) {
|
| + DartType computeType(Element element) {
|
| if (Element.isInvalid(element)) return types.dynamicType;
|
| - Type result = element.computeType(compiler);
|
| + DartType result = element.computeType(compiler);
|
| return (result !== null) ? result : types.dynamicType;
|
| }
|
|
|
| - Type visitTypeAnnotation(TypeAnnotation node) {
|
| + DartType visitTypeAnnotation(TypeAnnotation node) {
|
| return elements.getType(node);
|
| }
|
|
|
| @@ -722,8 +723,8 @@ class TypeCheckerVisitor implements Visitor<Type> {
|
| return types.dynamicType;
|
| }
|
|
|
| - Type visitVariableDefinitions(VariableDefinitions node) {
|
| - Type type = analyzeWithDefault(node.type, types.dynamicType);
|
| + DartType visitVariableDefinitions(VariableDefinitions node) {
|
| + DartType type = analyzeWithDefault(node.type, types.dynamicType);
|
| if (type == types.voidType) {
|
| reportTypeWarning(node.type, MessageKind.VOID_VARIABLE);
|
| type = types.dynamicType;
|
| @@ -734,14 +735,14 @@ class TypeCheckerVisitor implements Visitor<Type> {
|
| compiler.ensure(initialization is Identifier
|
| || initialization is Send);
|
| if (initialization is Send) {
|
| - Type initializer = analyzeNonVoid(link.head);
|
| + DartType initializer = analyzeNonVoid(link.head);
|
| checkAssignable(node, type, initializer);
|
| }
|
| }
|
| return StatementType.NOT_RETURNING;
|
| }
|
|
|
| - Type visitWhile(While node) {
|
| + DartType visitWhile(While node) {
|
| checkCondition(node.condition);
|
| StatementType bodyType = analyze(node.body);
|
| Expression cond = node.condition.asParenthesizedExpression().expression;
|
| @@ -757,14 +758,14 @@ class TypeCheckerVisitor implements Visitor<Type> {
|
| }
|
| }
|
|
|
| - Type visitParenthesizedExpression(ParenthesizedExpression node) {
|
| + DartType visitParenthesizedExpression(ParenthesizedExpression node) {
|
| return analyze(node.expression);
|
| }
|
|
|
| - Type visitConditional(Conditional node) {
|
| + DartType visitConditional(Conditional node) {
|
| checkCondition(node.condition);
|
| - Type thenType = analyzeNonVoid(node.thenExpression);
|
| - Type elseType = analyzeNonVoid(node.elseExpression);
|
| + DartType thenType = analyzeNonVoid(node.thenExpression);
|
| + DartType elseType = analyzeNonVoid(node.elseExpression);
|
| if (types.isSubtype(thenType, elseType)) {
|
| return thenType;
|
| } else if (types.isSubtype(elseType, thenType)) {
|
| @@ -774,7 +775,7 @@ class TypeCheckerVisitor implements Visitor<Type> {
|
| }
|
| }
|
|
|
| - Type visitModifiers(Modifiers node) {}
|
| + DartType visitModifiers(Modifiers node) {}
|
|
|
| visitStringInterpolation(StringInterpolation node) {
|
| node.visitChildren(this);
|
|
|