blob: 0aef7bcb7de08c3ef0d123a617271b5931a35a67 [file] [log] [blame]
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.resolver;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import com.google.dart.compiler.DartCompilerContext;
import com.google.dart.compiler.ast.ASTVisitor;
import com.google.dart.compiler.ast.DartClass;
import com.google.dart.compiler.ast.DartFunctionTypeAlias;
import com.google.dart.compiler.ast.DartTypeNode;
import com.google.dart.compiler.ast.DartTypeParameter;
import com.google.dart.compiler.ast.DartUnit;
import com.google.dart.compiler.type.InterfaceType;
import com.google.dart.compiler.type.Type;
import com.google.dart.compiler.type.TypeKind;
import java.util.List;
import java.util.Set;
/**
* Resolves the super class, interfaces, default implementation and
* bounds type parameters of classes in a DartUnit.
*/
public class SupertypeResolver {
private static final Set<String> BLACK_LISTED_TYPES = ImmutableSet.of(
"dynamic",
"Function",
"bool",
"num",
"int",
"double",
"String");
private ResolutionContext topLevelContext;
private CoreTypeProvider typeProvider;
public void exec(DartUnit unit, DartCompilerContext context, CoreTypeProvider typeProvider) {
exec(unit, context, unit.getLibrary().getElement().getScope(), typeProvider);
}
public void exec(DartUnit unit, DartCompilerContext compilerContext, Scope libraryScope,
CoreTypeProvider typeProvider) {
this.typeProvider = typeProvider;
this.topLevelContext = new ResolutionContext(libraryScope, compilerContext, typeProvider);
unit.accept(new ClassElementResolver());
}
// Resolves super class, interfaces and default class of all classes.
private class ClassElementResolver extends ASTVisitor<Void> {
@Override
public Void visitClass(DartClass node) {
ClassElement classElement = node.getElement();
// Make sure that the type parameters are in scope before resolving the
// super class and interfaces
ResolutionContext classContext = topLevelContext.extend(classElement);
DartTypeNode superclassNode = node.getSuperclass();
InterfaceType supertype;
if (superclassNode == null) {
supertype = typeProvider.getObjectType();
if (supertype.equals(classElement.getType())) {
// Object has no supertype.
supertype = null;
}
} else {
supertype = classContext.resolveClass(superclassNode, false, false);
supertype.getClass(); // Quick null check.
}
if (supertype != null) {
if (Elements.isTypeNode(superclassNode, BLACK_LISTED_TYPES)
&& !Elements.isCoreLibrarySource(node.getSourceInfo().getSource())) {
topLevelContext.onError(
superclassNode,
ResolverErrorCode.BLACK_LISTED_EXTENDS,
superclassNode);
}
classElement.setSupertype(supertype);
} else {
assert classElement.getName().equals("Object") : classElement;
}
if (node.getDefaultClass() != null) {
Element defaultClassElement = classContext.resolveName(node.getDefaultClass().getExpression());
if (ElementKind.of(defaultClassElement).equals(ElementKind.CLASS)) {
Elements.setDefaultClass(classElement, (InterfaceType)defaultClassElement.getType());
node.getDefaultClass().setType(defaultClassElement.getType());
}
}
if (node.getInterfaces() != null) {
Set<InterfaceType> seenImplement = Sets.newHashSet();
for (DartTypeNode intNode : node.getInterfaces()) {
InterfaceType intType = classContext.resolveInterface(intNode, false, false);
// May be type which can not be used as interface.
if (Elements.isTypeNode(intNode, BLACK_LISTED_TYPES)
&& !Elements.isCoreLibrarySource(node.getSourceInfo().getSource())) {
topLevelContext.onError(intNode, ResolverErrorCode.BLACK_LISTED_IMPLEMENTS, intNode);
continue;
}
// May be unresolved type, error already reported, ignore.
if (intType.getKind() == TypeKind.DYNAMIC) {
continue;
}
// check for uniqueness
if (!classElement.isInterface()) {
if (seenImplement.contains(intType)) {
topLevelContext.onError(intNode, ResolverErrorCode.DUPLICATE_IMPLEMENTS_TYPE);
continue;
}
seenImplement.add(intType);
}
// OK, add
Elements.addInterface(classElement, intType);
}
}
setBoundsOnTypeParameters(classElement.getTypeParameters(), classContext);
return null;
}
@Override
public Void visitFunctionTypeAlias(DartFunctionTypeAlias node) {
ResolutionContext resolutionContext = topLevelContext.extend(node.getElement());
Elements.addInterface(node.getElement(), typeProvider.getFunctionType());
setBoundsOnTypeParameters(node.getElement().getTypeParameters(), resolutionContext);
return null;
}
}
private void setBoundsOnTypeParameters(List<Type> typeParameters,
ResolutionContext resolutionContext) {
for (Type typeParameter : typeParameters) {
TypeVariableNodeElement variable = (TypeVariableNodeElement) typeParameter.getElement();
DartTypeParameter typeParameterNode = (DartTypeParameter) variable.getNode();
DartTypeNode boundNode = typeParameterNode.getBound();
if (boundNode != null) {
Type bound =
resolutionContext.resolveType(
boundNode,
false,
false,
true,
ResolverErrorCode.NO_SUCH_TYPE,
ResolverErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS);
boundNode.setType(bound);
}
}
}
}