mirror of
https://github.com/dart-lang/sdk
synced 2024-09-15 21:20:36 +00:00
Add support for --enable_type_checks (developer mode) for dartc.
This patch is based on https://chromereviews.googleplex.com/3520019/. However it addresses the following issues: 1) TypeError exceptions will now have the stack trace filled in. 2) Type parameters are now accessible from closurized code, including the trampoline shims for named optinal parameters. 3) Suppress use of FunctionExpressionInliner with type checks because the inline normalization can leave return nodes in the AST. 4) Pass the generateHumanReadableOutput flag to the closure backend. 5) TypeDartcTest passes in debug and release modes with type checking enabled. We still need to enable the additional cases in the code. Review URL: https://chromereviews.googleplex.com/3558021 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@271 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
parent
179f836439
commit
fc7390d97b
|
@ -38,6 +38,9 @@ public class CommandLineOptions {
|
|||
usage = "do not generate output, only analyze")
|
||||
private boolean checkOnly = false;
|
||||
|
||||
@Option(name = "--enable_type_checks", usage = "generate runtime type checks")
|
||||
private boolean developerModeChecks = false;
|
||||
|
||||
@Option(name = "--disable-type-optimizations",
|
||||
usage = "Debugging: disable type optimizations")
|
||||
private boolean disableTypeOptimizations = false;
|
||||
|
@ -252,6 +255,10 @@ public class CommandLineOptions {
|
|||
public boolean warningsAreFatal() {
|
||||
return warningsAreFatal;
|
||||
}
|
||||
|
||||
public boolean developerModeChecks() {
|
||||
return developerModeChecks;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -316,7 +323,7 @@ public class CommandLineOptions {
|
|||
|
||||
|
||||
/**
|
||||
* Command line options accepted by the {@link TestRunner} entry point.
|
||||
* Command line options accepted by the {@link com.google.dart.runner.TestRunner} entry point.
|
||||
*/
|
||||
public static class TestRunnerOptions extends DartRunnerOptions {
|
||||
}
|
||||
|
@ -329,8 +336,7 @@ public class CommandLineOptions {
|
|||
* for 'not a valid option' are suppressed.
|
||||
*
|
||||
* @param args Arguments passed from main()
|
||||
* @param cmdLineParser An initialized {@link CmdLineParser} for the desired
|
||||
* argument set.
|
||||
* @param parsedOptions [out parameter] parsed options
|
||||
* @throws CmdLineException Thrown if there is a problem parsing the options.
|
||||
*/
|
||||
public static CmdLineParser parse(String[] args, CompilerOptions parsedOptions)
|
||||
|
|
|
@ -20,6 +20,12 @@ public interface CompilerConfiguration {
|
|||
|
||||
List<Backend> getBackends();
|
||||
|
||||
/**
|
||||
* Indicates whether developer-mode runtime checks are needed.
|
||||
* @return true if developer-mode checks should be inserted, false if not
|
||||
*/
|
||||
boolean developerModeChecks();
|
||||
|
||||
/**
|
||||
* Returns <code>true</code> if the compiler's output should be optimized.
|
||||
*/
|
||||
|
|
|
@ -128,6 +128,11 @@ public class DefaultCompilerConfiguration implements CompilerConfiguration {
|
|||
return backends;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean developerModeChecks() {
|
||||
return compilerOptions.developerModeChecks();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldOptimize() {
|
||||
return compilerOptions.shouldOptimize();
|
||||
|
|
|
@ -22,6 +22,12 @@ public class DelegatingCompilerConfiguration implements CompilerConfiguration {
|
|||
public DelegatingCompilerConfiguration(CompilerConfiguration delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean developerModeChecks() {
|
||||
return delegate.developerModeChecks();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DartCompilationPhase> getPhases() {
|
||||
return delegate.getPhases();
|
||||
|
|
|
@ -331,8 +331,8 @@ public abstract class AbstractJsBackend extends AbstractBackend {
|
|||
unit.getSourceName()) : null;
|
||||
try {
|
||||
// Normalize front-end AST for back-end consumption.
|
||||
unit = (DartUnit) (new Normalizer()).exec(unit, typeProvider, optimizationStrategy)
|
||||
.getNormalizedNode();
|
||||
unit = (DartUnit) (new Normalizer()).exec(unit, typeProvider,
|
||||
optimizationStrategy).getNormalizedNode();
|
||||
} finally {
|
||||
Tracer.end(normalizeEvent);
|
||||
}
|
||||
|
|
|
@ -491,6 +491,12 @@ public class ClosureJsBackend extends AbstractJsBackend {
|
|||
// options.setShadowVariables(false);
|
||||
// options.inlineFunctions = false;
|
||||
|
||||
/*
|
||||
* NOTE: We turn this off because TypeErrors or anything that relies on a type name will fail
|
||||
* due to the renaming.
|
||||
*/
|
||||
options.setReplaceIdGenerators(false);
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
|
|
|
@ -269,7 +269,8 @@ public class GenerateJavascriptAST {
|
|||
// setup the global scope.
|
||||
jsNewDeclarationsStack.push(new HashSet<JsName>());
|
||||
currentHolder = unit.getLibrary().getElement();
|
||||
rtt = new RuntimeTypeInjector(this, typeProvider, translationContext);
|
||||
rtt = new RuntimeTypeInjector(this, typeProvider, translationContext,
|
||||
context.getCompilerConfiguration().developerModeChecks());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -958,7 +959,7 @@ public class GenerateJavascriptAST {
|
|||
|
||||
private JsNode generateConstructorDefinition(DartMethodDefinition x) {
|
||||
assert currentScopeInfo == null : "Nesting a constructor in a method should be impossible";
|
||||
currentScopeInfo = ScopeRootInfo.makeScopeInfo(x);
|
||||
currentScopeInfo = ScopeRootInfo.makeScopeInfo(x, !shouldGenerateDeveloperModeChecks());
|
||||
ConstructorElement element = (ConstructorElement) x.getSymbol();
|
||||
ClassElement classElement = (ClassElement) element.getEnclosingElement();
|
||||
JsScope classMemberScope = translationContext.getMemberScopes().get(classElement);
|
||||
|
@ -1088,7 +1089,7 @@ public class GenerateJavascriptAST {
|
|||
assert currentScopeInfo == null : "Nested methods should be impossible";
|
||||
inFactoryOrStaticContext = x.getModifiers().isFactory()
|
||||
|| x.getModifiers().isStatic();
|
||||
currentScopeInfo = ScopeRootInfo.makeScopeInfo(x);
|
||||
currentScopeInfo = ScopeRootInfo.makeScopeInfo(x, !shouldGenerateDeveloperModeChecks());
|
||||
|
||||
JsFunction func = (JsFunction) generate(x.getFunction());
|
||||
|
||||
|
@ -1555,7 +1556,7 @@ public class GenerateJavascriptAST {
|
|||
JsExprStmt result = null;
|
||||
|
||||
if (initializer != null || Elements.isTopLevel(element)) {
|
||||
currentScopeInfo = ScopeRootInfo.makeScopeInfo(x);
|
||||
currentScopeInfo = ScopeRootInfo.makeScopeInfo(x, !shouldGenerateDeveloperModeChecks());
|
||||
inFactoryOrStaticContext = true;
|
||||
|
||||
// There's an initializer, so emit an assignment statement.
|
||||
|
@ -1632,6 +1633,24 @@ public class GenerateJavascriptAST {
|
|||
}
|
||||
jsFunc.setBody(body);
|
||||
|
||||
// Create JS parameters
|
||||
List<DartParameter> params = x.getParams();
|
||||
List<JsParameter> jsParams = jsFunc.getParameters();
|
||||
generateAll(params, jsParams, JsParameter.class);
|
||||
|
||||
// Create the runtime type checks that will be inserted later
|
||||
List<JsStatement> checks = Lists.newArrayList();
|
||||
int numParams = params.size();
|
||||
for (int i = 0; i < numParams; ++i) {
|
||||
JsNameRef jsParam = jsParams.get(i).getName().makeRef();
|
||||
JsExpression expr = rtt.addTypeCheck(getCurrentClass(), jsParam,
|
||||
typeOf(params.get(i).getTypeNode()), null, params.get(i));
|
||||
if (expr != jsParam) {
|
||||
// if the expression was returned unchanged, omit the check
|
||||
checks.add(new JsExprStmt(expr));
|
||||
}
|
||||
}
|
||||
|
||||
// Add temporary variable declarations, if any.
|
||||
declareTempsInBlock(body, jsNewDeclarationsStack.pop());
|
||||
|
||||
|
@ -1654,16 +1673,29 @@ public class GenerateJavascriptAST {
|
|||
maybeAddFunctionScopeAlias(currentScopeInfo.getScope(x),
|
||||
translationContext.getMethods().get(x));
|
||||
|
||||
// 2. setup parameter values
|
||||
generateAll(x.getParams(), jsFunc.getParameters(), JsParameter.class);
|
||||
|
||||
// 1. call function trace before anything else.
|
||||
// 2. call function trace before anything else.
|
||||
maybeAddFunctionTracing(x);
|
||||
|
||||
// 1. insert parameter type checks at the beginning of the method
|
||||
body.getStatements().addAll(0, checks);
|
||||
|
||||
functionStack.pop();
|
||||
return jsFunc.setSourceRef(x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the type associated with a type node
|
||||
*
|
||||
* @param typeNode a {@link DartTypeNode}, which may be null
|
||||
* @return a {@link Type} corresponding to the type node or null to indicate unknown
|
||||
*/
|
||||
private Type typeOf(DartTypeNode typeNode) {
|
||||
if (typeNode == null) {
|
||||
return null;
|
||||
}
|
||||
return typeNode.getType();
|
||||
}
|
||||
|
||||
private boolean isFactory(DartMethodDefinition method) {
|
||||
return method.getModifiers().isFactory();
|
||||
}
|
||||
|
@ -1880,8 +1912,17 @@ public class GenerateJavascriptAST {
|
|||
@Override
|
||||
public JsNode visitReturnStatement(DartReturnStatement x) {
|
||||
JsReturn jsRet = new JsReturn();
|
||||
if (x.getValue() != null) {
|
||||
jsRet.setExpr((JsExpression) generate(x.getValue()));
|
||||
DartExpression returnValue = x.getValue();
|
||||
if (returnValue != null) {
|
||||
JsExpression expr = (JsExpression) generate(returnValue);
|
||||
DartFunction function = functionStack.peek();
|
||||
if (function != null) {
|
||||
// NOTE: FunctionExpressionInliner might be leaving return statements around
|
||||
DartTypeNode returnType = function.getReturnTypeNode();
|
||||
expr = rtt.addTypeCheck(getCurrentClass(), expr, typeOf(returnType),
|
||||
returnValue.getType(), x);
|
||||
}
|
||||
jsRet.setExpr(expr);
|
||||
}
|
||||
return jsRet.setSourceRef(x);
|
||||
}
|
||||
|
@ -2016,9 +2057,12 @@ public class GenerateJavascriptAST {
|
|||
// If the name is referenced by a closure use the scope alias.
|
||||
JsNameRef scopeAliasRef = maybeMakeScopeAliasReference(targetSymbol);
|
||||
JsNode result = null;
|
||||
DartExpression value = x.getValue();
|
||||
if (scopeAliasRef != null) {
|
||||
if (x.getValue() != null) {
|
||||
JsExpression initExpr = (JsExpression) generate(x.getValue());
|
||||
if (value != null) {
|
||||
JsExpression initExpr = (JsExpression) generate(value);
|
||||
Type type = getTypeOfIdentifier(x.getName());
|
||||
initExpr = rtt.addTypeCheck(getCurrentClass(), initExpr, type, value.getType(), x);
|
||||
result = AstUtil.newAssignment(scopeAliasRef, initExpr).setSourceRef(x).makeStmt();
|
||||
} else {
|
||||
// we need to put some statement in to keep the expected number
|
||||
|
@ -2027,8 +2071,10 @@ public class GenerateJavascriptAST {
|
|||
}
|
||||
} else {
|
||||
JsVars.JsVar jsVar = new JsVars.JsVar(getJsName(targetSymbol));
|
||||
if (x.getValue() != null) {
|
||||
JsExpression initExpr = (JsExpression) generate(x.getValue());
|
||||
if (value != null) {
|
||||
JsExpression initExpr = (JsExpression) generate(value);
|
||||
Type type = getTypeOfIdentifier(x.getName());
|
||||
initExpr = rtt.addTypeCheck(getCurrentClass(), initExpr, type, value.getType(), x);
|
||||
jsVar.setInitExpr(initExpr);
|
||||
} else {
|
||||
jsVar.setInitExpr(undefined());
|
||||
|
@ -2106,9 +2152,10 @@ public class GenerateJavascriptAST {
|
|||
return generateInstanceOfComparison(x);
|
||||
}
|
||||
|
||||
JsExpression rhs = (JsExpression) generate(x.getArg2());
|
||||
DartExpression arg2 = x.getArg2();
|
||||
JsExpression rhs = (JsExpression) generate(arg2);
|
||||
if (operator == Token.ASSIGN) {
|
||||
return x.getArg1().accept(new Assignment(x, rhs));
|
||||
return x.getArg1().accept(new Assignment(x, rhs, arg2.getType()));
|
||||
}
|
||||
|
||||
assert !operator.isUserDefinableOperator() || !operator.isAssignmentOperator() : x;
|
||||
|
@ -2129,7 +2176,7 @@ public class GenerateJavascriptAST {
|
|||
// TODO (fabiomfv) - This optimization targets a v8 perf issue. V8 double equals
|
||||
// comparison to undefined is up to 4 times slower than == null. It seems that it was
|
||||
// fixed on v8 3.5. once we move to 3.5 and the fix confirmed, this should be revisited.
|
||||
if (x.getArg2() instanceof DartNullLiteral) {
|
||||
if (arg2 instanceof DartNullLiteral) {
|
||||
op = mapToNonStrictEquals(op);
|
||||
rhs = nulle();
|
||||
}
|
||||
|
@ -2150,6 +2197,41 @@ public class GenerateJavascriptAST {
|
|||
}
|
||||
}
|
||||
|
||||
private Type getTypeOfIdentifier(DartIdentifier ident) {
|
||||
Element element = ident.getReferencedElement();
|
||||
DartTypeNode typeNode = null;
|
||||
if (element == null) {
|
||||
DartNode parent = ident.getParent();
|
||||
if (parent instanceof DartVariable) {
|
||||
DartVariableStatement varStmt = (DartVariableStatement) parent.getParent();
|
||||
typeNode = varStmt.getTypeNode();
|
||||
} else {
|
||||
throw new InternalCompilerException("Unexpected identifier type: " + ident);
|
||||
}
|
||||
} else {
|
||||
switch (element.getKind()) {
|
||||
case VARIABLE:
|
||||
DartVariableStatement varStmt = (DartVariableStatement) element.getNode().getParent();
|
||||
typeNode = varStmt.getTypeNode();
|
||||
break;
|
||||
case PARAMETER:
|
||||
DartParameter param = (DartParameter) element.getNode();
|
||||
typeNode = param.getTypeNode();
|
||||
break;
|
||||
case FIELD:
|
||||
DartFieldDefinition fieldDef = (DartFieldDefinition) element.getNode().getParent();
|
||||
typeNode = fieldDef.getTypeNode();
|
||||
break;
|
||||
default:
|
||||
throw new InternalCompilerException("Unexpected identifier element type " + element);
|
||||
}
|
||||
}
|
||||
if (typeNode != null) {
|
||||
return typeNode.getType();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private JsExpression generateInstanceOfComparison(DartBinaryExpression x) {
|
||||
JsExpression lhs = (JsExpression) generate(x.getArg1());
|
||||
DartExpression rhs = x.getArg2();
|
||||
|
@ -2335,7 +2417,9 @@ public class GenerateJavascriptAST {
|
|||
DartExpression target = x.getTarget();
|
||||
if (target instanceof DartFunctionExpression) {
|
||||
DartFunctionExpression functionExpression = (DartFunctionExpression) target;
|
||||
if (functionExpression.getSymbol().getModifiers().isInlinable()) {
|
||||
if (functionExpression.getSymbol().getModifiers().isInlinable() &&
|
||||
!shouldGenerateDeveloperModeChecks()) {
|
||||
// TODO FunctionExpressionInliner conflics with developer mode checks
|
||||
return new FunctionExpressionInliner(functionExpression, x.getArgs()).call();
|
||||
}
|
||||
}
|
||||
|
@ -2707,6 +2791,18 @@ public class GenerateJavascriptAST {
|
|||
return intern;
|
||||
}
|
||||
|
||||
private boolean shouldBindThis(ScopeRootInfo.ClosureInfo info) {
|
||||
if (shouldGenerateDeveloperModeChecks()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return !inFactoryOrStaticContext && info.referencesThis;
|
||||
}
|
||||
|
||||
private boolean shouldGenerateDeveloperModeChecks() {
|
||||
return context.getCompilerConfiguration().developerModeChecks();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsNode visitFunctionExpression(DartFunctionExpression x) {
|
||||
JsFunction fn = (JsFunction) generate(x.getFunction());
|
||||
|
@ -2751,7 +2847,7 @@ public class GenerateJavascriptAST {
|
|||
if (!fnWasPreviouslyHoisted) {
|
||||
// Generate the named-parameter trampoline.
|
||||
boolean includesClosureScope = !list.isEmpty();
|
||||
boolean preserveThis = !inFactoryOrStaticContext && info.referencesThis;
|
||||
boolean preserveThis = shouldBindThis(info);
|
||||
JsFunction tramp = generateNamedParameterTrampoline(x.getFunction(),
|
||||
hoistedName.makeRef(),
|
||||
list.size(), preserveThis);
|
||||
|
@ -2775,7 +2871,7 @@ public class GenerateJavascriptAST {
|
|||
|
||||
JsExpression thisRef = undefined();
|
||||
// Only bind 'this' if 'this' is referenced
|
||||
if (!inFactoryOrStaticContext && info.referencesThis) {
|
||||
if (shouldBindThis(info)) {
|
||||
thisRef = new JsThisRef();
|
||||
}
|
||||
|
||||
|
@ -3161,10 +3257,12 @@ public class GenerateJavascriptAST {
|
|||
class Assignment extends DartNodeTraverser<JsNode> {
|
||||
private final DartNode info;
|
||||
private final JsExpression rhs;
|
||||
private final Type rhsType;
|
||||
|
||||
public Assignment(DartNode info, JsExpression rhs) {
|
||||
public Assignment(DartNode info, JsExpression rhs, Type rhsType) {
|
||||
this.info = info;
|
||||
this.rhs = rhs;
|
||||
this.rhsType = rhsType;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -3178,16 +3276,21 @@ public class GenerateJavascriptAST {
|
|||
if (lhs != normalizedNode) {
|
||||
return normalizedNode.accept(this);
|
||||
}
|
||||
Type type = getTypeOfIdentifier(lhs);
|
||||
JsExpression wrapped = rtt.addTypeCheck(getCurrentClass(), rhs, type, rhsType, info);
|
||||
Element element = optStrategy.findOptimizableFieldElementFor(lhs, FieldKind.SETTER);
|
||||
// On the form e1.name = rhs.
|
||||
return generateStore(null, lhs, rhs, element).setSourceRef(info);
|
||||
return generateStore(null, lhs, wrapped, element).setSourceRef(info);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsNode visitPropertyAccess(DartPropertyAccess lhs) {
|
||||
Element element = optStrategy.findOptimizableFieldElementFor(lhs, FieldKind.SETTER);
|
||||
// On the form e1.name = rhs.
|
||||
return generateStore(lhs.getQualifier(), lhs.getName(), rhs, element).setSourceRef(info);
|
||||
Type type = lhs.getType();
|
||||
JsExpression wrapped = rtt.addTypeCheck(getCurrentClass(), rhs, type, rhsType, info);
|
||||
return generateStore(lhs.getQualifier(), lhs.getName(), wrapped,
|
||||
element).setSourceRef(info);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -3197,16 +3300,18 @@ public class GenerateJavascriptAST {
|
|||
|
||||
JsExpression key = (JsExpression) generate(lhs.getKey());
|
||||
JsExpression e1 = (JsExpression) generate(lhs.getTarget());
|
||||
Type type = lhs.getType();
|
||||
JsExpression wrapped = rtt.addTypeCheck(getCurrentClass(), rhs, type, rhsType, info);
|
||||
if (optStrategy.canSkipArrayAccessShim(lhs, true /* isAssignee */)) {
|
||||
JsBinaryOperation assign = new JsBinaryOperation(JsBinaryOperator.ASG);
|
||||
assign.setArg1(AstUtil.newArrayAccess(e1, inlineArrayIndexCheck(e1, key)));
|
||||
assign.setArg2(rhs);
|
||||
assign.setArg2(wrapped);
|
||||
return assign.setSourceRef(info);
|
||||
} else {
|
||||
JsNameRef $0 = new JsNameRef(createTemporary());
|
||||
String $set = mangler.createOperatorSyntax(Token.ASSIGN_INDEX);
|
||||
// Generate: $0 = rhs
|
||||
JsExpression e = AstUtil.newAssignment($0, rhs);
|
||||
JsExpression e = AstUtil.newAssignment($0, wrapped);
|
||||
// Generate: e1.$set(key, $0 = rhs)
|
||||
e = AstUtil.newInvocation(AstUtil.newNameRef(e1, $set), key, e);
|
||||
// Generate: e, $0
|
||||
|
|
|
@ -57,6 +57,7 @@ import com.google.dart.compiler.resolver.ClassElement;
|
|||
import com.google.dart.compiler.resolver.ConstructorElement;
|
||||
import com.google.dart.compiler.resolver.CoreTypeProvider;
|
||||
import com.google.dart.compiler.resolver.ElementKind;
|
||||
import com.google.dart.compiler.type.DynamicType;
|
||||
import com.google.dart.compiler.type.FunctionType;
|
||||
import com.google.dart.compiler.type.InterfaceType;
|
||||
import com.google.dart.compiler.type.Type;
|
||||
|
@ -76,6 +77,7 @@ import java.util.Set;
|
|||
* @author johnlenz@google.com (John Lenz)
|
||||
*/
|
||||
public class RuntimeTypeInjector {
|
||||
private final boolean emitTypeChecks;
|
||||
private final TraversalContextProvider context;
|
||||
private final JsBlock globalBlock;
|
||||
private final JsScope globalScope;
|
||||
|
@ -87,7 +89,7 @@ public class RuntimeTypeInjector {
|
|||
RuntimeTypeInjector(
|
||||
TraversalContextProvider context,
|
||||
CoreTypeProvider typeProvider,
|
||||
TranslationContext translationContext) {
|
||||
TranslationContext translationContext, boolean emitTypeChecks) {
|
||||
this.context = context;
|
||||
this.translationContext = translationContext;
|
||||
JsProgram program = translationContext.getProgram();
|
||||
|
@ -95,6 +97,7 @@ public class RuntimeTypeInjector {
|
|||
this.globalScope = program.getScope();
|
||||
this.builtinTypes = makeBuiltinTypes(typeProvider);
|
||||
this.typeProvider = typeProvider;
|
||||
this.emitTypeChecks = emitTypeChecks;
|
||||
}
|
||||
|
||||
private Map<ClassElement, String> makeBuiltinTypes(CoreTypeProvider typeProvider) {
|
||||
|
@ -744,8 +747,7 @@ public class RuntimeTypeInjector {
|
|||
return call(src, nameref(src, rtt, "implementedBy"), lhs);
|
||||
}
|
||||
|
||||
private JsExpression generateRefiedTypeVariableComparison(
|
||||
JsExpression lhs, TypeVariable type, ClassElement contextClassElement, SourceInfo src) {
|
||||
private JsExpression getReifiedTypeVariableRTT(TypeVariable type, ClassElement contextClassElement) {
|
||||
JsExpression rttContext;
|
||||
if (!inFactory()) {
|
||||
// build: this.typeinfo.implementedTypes['class'].typeArgs;
|
||||
|
@ -756,6 +758,12 @@ public class RuntimeTypeInjector {
|
|||
}
|
||||
// rtt = rttContext.typeArgs[x]
|
||||
JsExpression rtt = buildTypeLookupExpression(type, contextClassElement.getTypeParameters(), rttContext);
|
||||
return rtt;
|
||||
}
|
||||
|
||||
private JsExpression generateRefiedTypeVariableComparison(
|
||||
JsExpression lhs, TypeVariable type, ClassElement contextClassElement, SourceInfo src) {
|
||||
JsExpression rtt = getReifiedTypeVariableRTT(type, contextClassElement);
|
||||
return call(src, nameref(src, rtt, "implementedBy"), lhs);
|
||||
}
|
||||
|
||||
|
@ -806,4 +814,128 @@ public class RuntimeTypeInjector {
|
|||
|| member.getModifiers().isFactory()
|
||||
|| member.getModifiers().isStatic();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Optionally emit a runtime type check, which is a call to $chk passing the
|
||||
* runtime type object for the required type and an expression.
|
||||
*
|
||||
* @param enclosingClass enclosing class element
|
||||
* @param expr expression to check
|
||||
* @param type {@link Type} to check against, null is unknown
|
||||
* @param src source info to use for the generated code
|
||||
* @return an expression wrapping the type check call
|
||||
*/
|
||||
JsExpression addTypeCheck(ClassElement enclosingClass, JsExpression expr, Type type,
|
||||
Type exprType, SourceInfo src) {
|
||||
if (!emitTypeChecks || isStaticallyGoodAssignment(type, exprType)) {
|
||||
return expr;
|
||||
}
|
||||
if (isStaticallyBadAssignment(type, exprType, expr)) {
|
||||
return injectTypeError(enclosingClass, expr, type, src);
|
||||
}
|
||||
return injectTypeCheck(enclosingClass, expr, type, src);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an assignment is statically known to have a type error.
|
||||
*
|
||||
* @param type
|
||||
* @param exprType
|
||||
* @param expr
|
||||
* @return true if the assignment is known to be bad statically
|
||||
*/
|
||||
private boolean isStaticallyBadAssignment(Type type, Type exprType, JsExpression expr) {
|
||||
if (!expr.isDefinitelyNotNull()) {
|
||||
// nulls can be assigned to any type, so if this may be null we can't assume it is a bad
|
||||
// assignment
|
||||
return false;
|
||||
}
|
||||
// TODO(jat): implement static subtype checks
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param type
|
||||
* @param exprType
|
||||
* @return true if the assignment is statically known to not need a check
|
||||
*/
|
||||
private boolean isStaticallyGoodAssignment(Type type, Type exprType) {
|
||||
if (type == null || type instanceof DynamicType) {
|
||||
// if there is no target type or it is dynamic, it is good
|
||||
return true;
|
||||
}
|
||||
// TODO(jat): implement static subtype checks
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Optionally emit a type error, used when it is statically known that a
|
||||
* TypeError must be thrown.
|
||||
*
|
||||
* @param enclosingClass enclosing class element
|
||||
* @param expr expression that fails the check
|
||||
* @param type type to check against, null is unknown
|
||||
* @param src source info to use for the generated code
|
||||
* @return an expression wrapping the call to the throw helper
|
||||
*/
|
||||
private JsExpression injectTypeError(ClassElement enclosingClass, JsExpression expr, Type type,
|
||||
SourceInfo src) {
|
||||
JsExpression rtt = getRtt(enclosingClass, expr, type);
|
||||
if (rtt != null) {
|
||||
expr = call(src, nameref(src, "$te"), rtt, expr);
|
||||
}
|
||||
return expr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Optionally emit a runtime type check, which is a call to $chk passing the
|
||||
* runtime type object for the required type and an expression.
|
||||
*
|
||||
* @param enclosingClass enclosing class element
|
||||
* @param expr expression to check
|
||||
* @param type type to check against, null is unknown
|
||||
* @param src source info to use for the generated code
|
||||
* @return an expression wrapping the type check call
|
||||
*/
|
||||
private JsExpression injectTypeCheck(ClassElement enclosingClass, JsExpression expr, Type type,
|
||||
SourceInfo src) {
|
||||
JsExpression rtt = getRtt(enclosingClass, expr, type);
|
||||
if (rtt != null) {
|
||||
expr = call(src, nameref(src, "$chk"), rtt, expr);
|
||||
}
|
||||
return expr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the runtime type object for a type.
|
||||
*
|
||||
* @param enclosingClass
|
||||
* @param expr
|
||||
* @param type
|
||||
* @return a {@link JsExpression} for the runtime type, or null if no check is required/possible
|
||||
*/
|
||||
private JsExpression getRtt(ClassElement enclosingClass, JsExpression expr, Type type) {
|
||||
if (!emitTypeChecks || type == null) {
|
||||
return null;
|
||||
}
|
||||
JsExpression rtt;
|
||||
switch (TypeKind.of(type)) {
|
||||
case INTERFACE:
|
||||
InterfaceType interfaceType = (InterfaceType) type;
|
||||
// TODO(jat): do we need a special case for raw interfaces?
|
||||
return generateRTTLookup(interfaceType, enclosingClass);
|
||||
case VARIABLE:
|
||||
TypeVariable typeVar = (TypeVariable) type;
|
||||
return getReifiedTypeVariableRTT(typeVar, enclosingClass);
|
||||
case VOID:
|
||||
case FUNCTION_ALIAS:
|
||||
// TODO(jat): implement, no checks for now
|
||||
case DYNAMIC:
|
||||
// no check required
|
||||
return null;
|
||||
default:
|
||||
throw new IllegalStateException("unexpected type " + type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ import com.google.dart.compiler.ast.DartMethodDefinition;
|
|||
import com.google.dart.compiler.ast.DartNode;
|
||||
import com.google.dart.compiler.ast.DartParameter;
|
||||
import com.google.dart.compiler.ast.DartThisExpression;
|
||||
import com.google.dart.compiler.ast.DartTypeParameter;
|
||||
import com.google.dart.compiler.ast.DartUnit;
|
||||
import com.google.dart.compiler.ast.DartVariable;
|
||||
import com.google.dart.compiler.backend.js.ast.JsName;
|
||||
|
@ -308,9 +309,11 @@ class ScopeRootInfo {
|
|||
private Deque<DartScope> scopeStack = Lists.newLinkedList();
|
||||
private final Map<DartFunction, ScopeRootInfo.ClosureInfo> closures = Maps.newHashMap();
|
||||
private Deque<DartFunction> closureStack = Lists.newLinkedList();
|
||||
|
||||
ClosureRefenceMapBuilder(Map<DartNode, DartScope> scopes) {
|
||||
private final boolean respectInlinableModifier;
|
||||
|
||||
ClosureRefenceMapBuilder(Map<DartNode, DartScope> scopes, boolean respectInlinableModifier) {
|
||||
this.scopes = scopes;
|
||||
this.respectInlinableModifier = respectInlinableModifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -329,7 +332,8 @@ class ScopeRootInfo {
|
|||
DartExpression target = x.getTarget();
|
||||
if (target instanceof DartFunctionExpression) {
|
||||
DartFunctionExpression functionExpression = (DartFunctionExpression) target;
|
||||
if (functionExpression.getSymbol().getModifiers().isInlinable()) {
|
||||
if (respectInlinableModifier &&
|
||||
functionExpression.getSymbol().getModifiers().isInlinable()) {
|
||||
acceptList(x.getArgs());
|
||||
return traverseFunction(functionExpression.getFunction(), ctx);
|
||||
}
|
||||
|
@ -471,19 +475,20 @@ class ScopeRootInfo {
|
|||
private final Map<DartNode, DartScope> scopes;
|
||||
private int closureIds = 0;
|
||||
|
||||
static ScopeRootInfo makeScopeInfo(DartMethodDefinition x) {
|
||||
return makeScopeInfoImpl(x);
|
||||
static ScopeRootInfo makeScopeInfo(DartMethodDefinition x, boolean respectInlinableModifier) {
|
||||
return makeScopeInfoImpl(x, respectInlinableModifier);
|
||||
}
|
||||
|
||||
static ScopeRootInfo makeScopeInfo(DartField x) {
|
||||
return makeScopeInfoImpl(x);
|
||||
static ScopeRootInfo makeScopeInfo(DartField x, boolean respectInlinableModifier) {
|
||||
return makeScopeInfoImpl(x, respectInlinableModifier);
|
||||
}
|
||||
|
||||
private static ScopeRootInfo makeScopeInfoImpl(DartClassMember<?> x) {
|
||||
private static ScopeRootInfo makeScopeInfoImpl(DartClassMember<?> x,
|
||||
boolean respectInlinableModifier) {
|
||||
ScopeRootInfo.MethodScopeMapBuilder scopeBuilder = new MethodScopeMapBuilder();
|
||||
scopeBuilder.accept(x);
|
||||
ScopeRootInfo.ClosureRefenceMapBuilder closureBuilder = new ClosureRefenceMapBuilder(
|
||||
scopeBuilder.scopes);
|
||||
scopeBuilder.scopes, respectInlinableModifier);
|
||||
closureBuilder.accept(x);
|
||||
return new ScopeRootInfo(x, scopeBuilder.scopes, closureBuilder.closures);
|
||||
}
|
||||
|
@ -525,4 +530,4 @@ class ScopeRootInfo {
|
|||
public String getNextClosureName() {
|
||||
return "c" + closureIds++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,11 @@ import java.util.List;
|
|||
public class TestCompilerConfiguration implements CompilerConfiguration {
|
||||
private final SystemLibraryManager systemLibraryManager = new SystemLibraryManager();
|
||||
|
||||
@Override
|
||||
public boolean developerModeChecks() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean warningsAreFatal() {
|
||||
return false;
|
||||
|
|
|
@ -311,7 +311,7 @@ public class DartRunner {
|
|||
final DartRunnerOptions options, DartCompilerListener listener) throws RunnerError {
|
||||
Backend backend;
|
||||
if (options.shouldOptimize()) {
|
||||
backend = new ClosureJsBackend();
|
||||
backend = new ClosureJsBackend(options.generateHumanReadableOutput());
|
||||
} else {
|
||||
backend = new JavascriptBackend();
|
||||
}
|
||||
|
|
|
@ -2,17 +2,33 @@
|
|||
// 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.
|
||||
|
||||
// Exceptions thrown by the VM.
|
||||
// Exceptions thrown by the VM -- user code should never throw these directly.
|
||||
// TODO(jat): these should be compatible with the definitions in runtime/lib/error.dart
|
||||
|
||||
class AssertionError {
|
||||
const AssertionError();
|
||||
|
||||
String toString() {
|
||||
return "Failed assertion";
|
||||
}
|
||||
}
|
||||
|
||||
class TypeError extends AssertionError {
|
||||
const TypeError() : super();
|
||||
final String dstType;
|
||||
final String srcType;
|
||||
|
||||
const TypeError(this.srcType, this.dstType);
|
||||
|
||||
String toString() {
|
||||
return "Failed type check: type $srcType is not assignable to type $dstType";
|
||||
}
|
||||
}
|
||||
|
||||
class FallThroughError {
|
||||
const FallThroughError() : super();
|
||||
const FallThroughError();
|
||||
|
||||
String toString() {
|
||||
return "Switch case fall-through";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -36,6 +36,10 @@ class ExceptionHelper {
|
|||
receiver, functionName, arguments) native {
|
||||
return new NoSuchMethodException(receiver, functionName, arguments);
|
||||
}
|
||||
|
||||
static TypeError createTypeError(String srcType, String dstType) native {
|
||||
return new TypeError(srcType, dstType);
|
||||
}
|
||||
}
|
||||
|
||||
class _CoreJsUtil {
|
||||
|
|
|
@ -184,6 +184,7 @@ var $Dart$Null = void 0;
|
|||
function assert(expr, msg) {
|
||||
var val = typeof(expr) == 'function' ? expr() : expr;
|
||||
if (!val) {
|
||||
// TODO: throw a Dart AssertionError instead
|
||||
var err = new Error('Assertion failed. ' + (msg || ''));
|
||||
Error.captureStackTrace && Error.captureStackTrace(err);
|
||||
throw err;
|
||||
|
|
|
@ -75,6 +75,20 @@ RTT.prototype.implementedByType = function(otherType) {
|
|||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* @return {string} the class name associated with this type
|
||||
*/
|
||||
RTT.prototype.getClassName = function() {
|
||||
var name = this.classKey;
|
||||
if (name.substr(0, 4) == "cls:") {
|
||||
name = name.substr(4);
|
||||
}
|
||||
if (name.substr(-5) == "$Dart") {
|
||||
name = name.substr(0, name.length - 5);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {RTT}
|
||||
* @return {boolean}
|
||||
|
@ -208,6 +222,35 @@ RTT.placeholderType = new RTT($cls('::'));
|
|||
RTT.placeholderType.implementedBy = function(o) {return true};
|
||||
RTT.placeholderType.implementedByType = function(o) {return true};
|
||||
|
||||
/**
|
||||
* Checks that a value is assignable to an expected type, and either returns that
|
||||
* value if it is, or else throws a TypeMismatchException.
|
||||
*
|
||||
* @param {!RTT} the expected type
|
||||
* @param {*} the value to check
|
||||
* @return {*} the value
|
||||
*/
|
||||
function $chk(rtt, value) {
|
||||
// null can be assigned to any type
|
||||
if (value == $Dart$Null || rtt.implementedBy(value)) {
|
||||
return value;
|
||||
}
|
||||
$te(rtt, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Throw a TypeError. See core.dart for the ExceptionHelper class.
|
||||
*
|
||||
* @param {!RTT} the expected type
|
||||
* @param {*) the value that failed
|
||||
*/
|
||||
function $te(rtt, value) {
|
||||
var srcType = RTT.getTypeInfo(value).getClassName();
|
||||
var dstType = rtt.getClassName();
|
||||
var e = native_ExceptionHelper_createTypeError(srcType, dstType);
|
||||
$Dart$ThrowException(e);
|
||||
}
|
||||
|
||||
// Setup the Function object
|
||||
Function.prototype.$implements$Function$Dart = 1;
|
||||
RTT.setTypeInfo(Function.prototype, RTT.create($cls('Function$Dart')));
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// 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.
|
||||
// Errors are created and thrown by DartVM only.
|
||||
// Changes here should also be reflected in corelib/error.dart as well
|
||||
|
||||
class AssertError {
|
||||
factory AssertError._uninstantiable() {
|
||||
|
|
|
@ -131,7 +131,6 @@ CharEscapeTest: Fail
|
|||
FunctionTypeParameter2NegativeTest: Fail # Bug 4568007
|
||||
|
||||
# The following tests use missing error classes. Bug 4385894.
|
||||
TypeTest: Fail # Uses TypeError class.
|
||||
AssertTest: Fail # Uses AssertError class.
|
||||
|
||||
ThirdTest: Fail # Bug 5339586
|
||||
|
|
513
tests/language/src/TypeDartcTest.dart
Normal file
513
tests/language/src/TypeDartcTest.dart
Normal file
|
@ -0,0 +1,513 @@
|
|||
// Copyright (c) 2011, 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.
|
||||
// VMOptions=--enable_type_checks --enable_asserts
|
||||
//
|
||||
// Dart test program testing type checks.
|
||||
|
||||
class TypeTest {
|
||||
static test() {
|
||||
int result = 0;
|
||||
try {
|
||||
int i = "hello"; // Throws a TypeError if type checks are enabled.
|
||||
} catch (TypeError error) {
|
||||
result = 1;
|
||||
Expect.equals("int", error.dstType);
|
||||
Expect.equals("String", error.srcType);
|
||||
/*
|
||||
Expect.equals("i", error.dstName);
|
||||
int pos = error.url.lastIndexOf("/", error.url.length);
|
||||
if (pos == -1) {
|
||||
pos = error.url.lastIndexOf("\\", error.url.length);
|
||||
}
|
||||
String subs = error.url.substring(pos + 1, error.url.length);
|
||||
Expect.equals("TypeTest.dart", subs);
|
||||
Expect.equals(12, error.line);
|
||||
Expect.equals(15, error.column);
|
||||
*/
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static testSideEffect() {
|
||||
int result = 0;
|
||||
int index() {
|
||||
result++;
|
||||
return 0;
|
||||
}
|
||||
try {
|
||||
List<int> a = new List<int>(1);
|
||||
a[0] = 0;
|
||||
a[index()]++; // Type check succeeds, but does not create side effects.
|
||||
assert(a[0] == 1);
|
||||
} catch (TypeError error) {
|
||||
result = 100;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static testArgument() {
|
||||
int result = 0;
|
||||
int f(int i) {
|
||||
return i;
|
||||
}
|
||||
try {
|
||||
int i = f("hello"); // Throws a TypeError if type checks are enabled.
|
||||
} catch (TypeError error) {
|
||||
result = 1;
|
||||
Expect.equals("int", error.dstType);
|
||||
Expect.equals("String", error.srcType);
|
||||
/*
|
||||
Expect.equals("i", error.dstName);
|
||||
int pos = error.url.lastIndexOf("/", error.url.length);
|
||||
if (pos == -1) {
|
||||
pos = error.url.lastIndexOf("\\", error.url.length);
|
||||
}
|
||||
String subs = error.url.substring(pos + 1, error.url.length);
|
||||
Expect.equals("TypeTest.dart", subs);
|
||||
Expect.equals(49, error.line);
|
||||
Expect.equals(15, error.column);
|
||||
*/
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static testReturn() {
|
||||
int result = 0;
|
||||
int f(String s) {
|
||||
return s;
|
||||
}
|
||||
try {
|
||||
int i = f("hello"); // Throws a TypeError if type checks are enabled.
|
||||
} catch (TypeError error) {
|
||||
result = 1;
|
||||
Expect.equals("int", error.dstType);
|
||||
Expect.equals("String", error.srcType);
|
||||
/*
|
||||
Expect.equals("function result", error.dstName);
|
||||
int pos = error.url.lastIndexOf("/", error.url.length);
|
||||
if (pos == -1) {
|
||||
pos = error.url.lastIndexOf("\\", error.url.length);
|
||||
}
|
||||
String subs = error.url.substring(pos + 1, error.url.length);
|
||||
Expect.equals("TypeTest.dart", subs);
|
||||
Expect.equals(74, error.line);
|
||||
Expect.equals(14, error.column);
|
||||
*/
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static int field;
|
||||
static testField() {
|
||||
int result = 0;
|
||||
try {
|
||||
field = "hello"; // Throws a TypeError if type checks are enabled.
|
||||
} catch (TypeError error) {
|
||||
result = 1;
|
||||
Expect.equals("int", error.dstType);
|
||||
Expect.equals("String", error.srcType);
|
||||
/*
|
||||
Expect.equals("field", error.dstName);
|
||||
int pos = error.url.lastIndexOf("/", error.url.length);
|
||||
if (pos == -1) {
|
||||
pos = error.url.lastIndexOf("\\", error.url.length);
|
||||
}
|
||||
String subs = error.url.substring(pos + 1, error.url.length);
|
||||
Expect.equals("TypeTest.dart", subs);
|
||||
Expect.equals(99, error.line);
|
||||
Expect.equals(15, error.column);
|
||||
*/
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static testAnyFunction() {
|
||||
int result = 0;
|
||||
Function anyFunction;
|
||||
f() { };
|
||||
anyFunction = f; // No error.
|
||||
try {
|
||||
int i = f; // Throws a TypeError if type checks are enabled.
|
||||
} catch (TypeError error) {
|
||||
result = 1;
|
||||
Expect.equals("int", error.dstType);
|
||||
/*
|
||||
Expect.equals("() => var", error.srcType); TODO(regis): => Dynamic.
|
||||
Expect.equals("i", error.dstName);
|
||||
int pos = error.url.lastIndexOf("/", error.url.length);
|
||||
if (pos == -1) {
|
||||
pos = error.url.lastIndexOf("\\", error.url.length);
|
||||
}
|
||||
String subs = error.url.substring(pos + 1, error.url.length);
|
||||
Expect.equals("TypeTest.dart", subs);
|
||||
Expect.equals(123, error.line);
|
||||
Expect.equals(15, error.column);
|
||||
*/
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static testVoidFunction() {
|
||||
int result = 0;
|
||||
Function anyFunction;
|
||||
void acceptVoidFunObj(void voidFunObj(Object obj)) { };
|
||||
void acceptObjFunObj(Object objFunObj(Object obj)) { };
|
||||
void voidFunObj(Object obj) { };
|
||||
Object objFunObj(Object obj) { return obj; };
|
||||
anyFunction = voidFunObj; // No error.
|
||||
anyFunction = objFunObj; // No error.
|
||||
acceptVoidFunObj(voidFunObj);
|
||||
acceptVoidFunObj(objFunObj);
|
||||
acceptObjFunObj(objFunObj);
|
||||
try {
|
||||
acceptObjFunObj(voidFunObj); // Throws a TypeError.
|
||||
} catch (TypeError error) {
|
||||
result = 1;
|
||||
/*
|
||||
Expect.equals("(Object) => Object", error.dstType);
|
||||
Expect.equals("(Object) => void", error.srcType);
|
||||
Expect.equals("objFunObj", error.dstName);
|
||||
int pos = error.url.lastIndexOf("/", error.url.length);
|
||||
if (pos == -1) {
|
||||
pos = error.url.lastIndexOf("\\", error.url.length);
|
||||
}
|
||||
String subs = error.url.substring(pos + 1, error.url.length);
|
||||
Expect.equals("TypeTest.dart", subs);
|
||||
Expect.equals(145, error.line);
|
||||
Expect.equals(33, error.column);
|
||||
*/
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static testFunctionNum() {
|
||||
int result = 0;
|
||||
Function anyFunction;
|
||||
void acceptFunNum(void funNum(num num)) { };
|
||||
void funObj(Object obj) { };
|
||||
void funNum(num num) { };
|
||||
void funInt(int i) { };
|
||||
void funString(String s) { };
|
||||
anyFunction = funObj; // No error.
|
||||
anyFunction = funNum; // No error.
|
||||
anyFunction = funInt; // No error.
|
||||
anyFunction = funString; // No error.
|
||||
acceptFunNum(funObj); // No error.
|
||||
acceptFunNum(funNum); // No error.
|
||||
acceptFunNum(funInt); // No error.
|
||||
try {
|
||||
acceptFunNum(funString); // Throws an error.
|
||||
} catch (TypeError error) {
|
||||
result = 1;
|
||||
/*
|
||||
Expect.equals("(num) => void", error.dstType);
|
||||
Expect.equals("(String) => void", error.srcType);
|
||||
Expect.equals("funNum", error.dstName);
|
||||
int pos = error.url.lastIndexOf("/", error.url.length);
|
||||
if (pos == -1) {
|
||||
pos = error.url.lastIndexOf("\\", error.url.length);
|
||||
}
|
||||
String subs = error.url.substring(pos + 1, error.url.length);
|
||||
Expect.equals("TypeTest.dart", subs);
|
||||
Expect.equals(175, error.line);
|
||||
Expect.equals(28, error.column);
|
||||
*/
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static testBoolCheck() {
|
||||
int result = 0;
|
||||
try {
|
||||
bool i = !"hello"; // Throws a TypeError if type checks are enabled.
|
||||
} catch (TypeError error) {
|
||||
result++;
|
||||
Expect.equals("bool", error.dstType);
|
||||
Expect.equals("String", error.srcType);
|
||||
/*
|
||||
Expect.equals("boolean expression", error.dstName);
|
||||
int pos = error.url.lastIndexOf("/", error.url.length);
|
||||
if (pos == -1) {
|
||||
pos = error.url.lastIndexOf("\\", error.url.length);
|
||||
}
|
||||
String subs = error.url.substring(pos + 1, error.url.length);
|
||||
Expect.equals("TypeTest.dart", subs);
|
||||
Expect.equals(209, error.line);
|
||||
Expect.equals(17, error.column);
|
||||
*/
|
||||
}
|
||||
try {
|
||||
while ("hello") {}; // Throws a TypeError if type checks are enabled.
|
||||
} catch (TypeError error) {
|
||||
result++;
|
||||
Expect.equals("bool", error.dstType);
|
||||
Expect.equals("String", error.srcType);
|
||||
/*
|
||||
Expect.equals("boolean expression", error.dstName);
|
||||
int pos = error.url.lastIndexOf("/", error.url.length);
|
||||
if (pos == -1) {
|
||||
pos = error.url.lastIndexOf("\\", error.url.length);
|
||||
}
|
||||
String subs = error.url.substring(pos + 1, error.url.length);
|
||||
Expect.equals("TypeTest.dart", subs);
|
||||
Expect.equals(225, error.line);
|
||||
Expect.equals(14, error.column);
|
||||
*/
|
||||
}
|
||||
try {
|
||||
do {} while ("hello"); // Throws a TypeError if type checks are enabled.
|
||||
} catch (TypeError error) {
|
||||
result++;
|
||||
Expect.equals("bool", error.dstType);
|
||||
Expect.equals("String", error.srcType);
|
||||
/*
|
||||
Expect.equals("boolean expression", error.dstName);
|
||||
int pos = error.url.lastIndexOf("/", error.url.length);
|
||||
if (pos == -1) {
|
||||
pos = error.url.lastIndexOf("\\", error.url.length);
|
||||
}
|
||||
String subs = error.url.substring(pos + 1, error.url.length);
|
||||
Expect.equals("TypeTest.dart", subs);
|
||||
Expect.equals(241, error.line);
|
||||
Expect.equals(20, error.column);
|
||||
*/
|
||||
}
|
||||
try {
|
||||
for (;"hello";) {}; // Throws a TypeError if type checks are enabled.
|
||||
} catch (TypeError error) {
|
||||
result++;
|
||||
Expect.equals("bool", error.dstType);
|
||||
Expect.equals("String", error.srcType);
|
||||
/*
|
||||
Expect.equals("boolean expression", error.dstName);
|
||||
int pos = error.url.lastIndexOf("/", error.url.length);
|
||||
if (pos == -1) {
|
||||
pos = error.url.lastIndexOf("\\", error.url.length);
|
||||
}
|
||||
String subs = error.url.substring(pos + 1, error.url.length);
|
||||
Expect.equals("TypeTest.dart", subs);
|
||||
Expect.equals(257, error.line);
|
||||
Expect.equals(13, error.column);
|
||||
*/
|
||||
}
|
||||
try {
|
||||
int i = "hello" ? 1 : 0; // Throws a TypeError if type checks are enabled.
|
||||
} catch (TypeError error) {
|
||||
result++;
|
||||
Expect.equals("bool", error.dstType);
|
||||
Expect.equals("String", error.srcType);
|
||||
/*
|
||||
Expect.equals("boolean expression", error.dstName);
|
||||
int pos = error.url.lastIndexOf("/", error.url.length);
|
||||
if (pos == -1) {
|
||||
pos = error.url.lastIndexOf("\\", error.url.length);
|
||||
}
|
||||
String subs = error.url.substring(pos + 1, error.url.length);
|
||||
Expect.equals("TypeTest.dart", subs);
|
||||
Expect.equals(273, error.line);
|
||||
Expect.equals(15, error.column);
|
||||
*/
|
||||
}
|
||||
try {
|
||||
if ("hello") {}; // Throws a TypeError if type checks are enabled.
|
||||
} catch (TypeError error) {
|
||||
result++;
|
||||
Expect.equals("bool", error.dstType);
|
||||
Expect.equals("String", error.srcType);
|
||||
/*
|
||||
Expect.equals("boolean expression", error.dstName);
|
||||
int pos = error.url.lastIndexOf("/", error.url.length);
|
||||
if (pos == -1) {
|
||||
pos = error.url.lastIndexOf("\\", error.url.length);
|
||||
}
|
||||
String subs = error.url.substring(pos + 1, error.url.length);
|
||||
Expect.equals("TypeTest.dart", subs);
|
||||
Expect.equals(289, error.line);
|
||||
Expect.equals(11, error.column);
|
||||
*/
|
||||
}
|
||||
try {
|
||||
if ("hello" || false) {}; // Throws a TypeError if type checks are enabled.
|
||||
} catch (TypeError error) {
|
||||
result++;
|
||||
Expect.equals("bool", error.dstType);
|
||||
Expect.equals("String", error.srcType);
|
||||
/*
|
||||
Expect.equals("boolean expression", error.dstName);
|
||||
int pos = error.url.lastIndexOf("/", error.url.length);
|
||||
if (pos == -1) {
|
||||
pos = error.url.lastIndexOf("\\", error.url.length);
|
||||
}
|
||||
String subs = error.url.substring(pos + 1, error.url.length);
|
||||
Expect.equals("TypeTest.dart", subs);
|
||||
Expect.equals(305, error.line);
|
||||
Expect.equals(11, error.column);
|
||||
*/
|
||||
}
|
||||
try {
|
||||
if (false || "hello") {}; // Throws a TypeError if type checks are enabled.
|
||||
} catch (TypeError error) {
|
||||
result++;
|
||||
Expect.equals("bool", error.dstType);
|
||||
Expect.equals("String", error.srcType);
|
||||
/*
|
||||
Expect.equals("boolean expression", error.dstName);
|
||||
int pos = error.url.lastIndexOf("/", error.url.length);
|
||||
if (pos == -1) {
|
||||
pos = error.url.lastIndexOf("\\", error.url.length);
|
||||
}
|
||||
String subs = error.url.substring(pos + 1, error.url.length);
|
||||
Expect.equals("TypeTest.dart", subs);
|
||||
Expect.equals(321, error.line);
|
||||
Expect.equals(20, error.column);
|
||||
*/
|
||||
}
|
||||
try {
|
||||
if (null) {}; // Throws a TypeError if type checks are enabled.
|
||||
} catch (TypeError error) {
|
||||
result++;
|
||||
Expect.equals("bool", error.dstType);
|
||||
Expect.equals("Null", error.srcType);
|
||||
/*
|
||||
Expect.equals("boolean expression", error.dstName);
|
||||
int pos = error.url.lastIndexOf("/", error.url.length);
|
||||
if (pos == -1) {
|
||||
pos = error.url.lastIndexOf("\\", error.url.length);
|
||||
}
|
||||
String subs = error.url.substring(pos + 1, error.url.length);
|
||||
Expect.equals("TypeTest.dart", subs);
|
||||
Expect.equals(337, error.line);
|
||||
Expect.equals(11, error.column);
|
||||
*/
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static int testFactory() {
|
||||
int result = 0;
|
||||
try {
|
||||
var x = new C();
|
||||
} catch (TypeError error) {
|
||||
result++;
|
||||
Expect.equals("C", error.dstType);
|
||||
Expect.equals("Smi", error.srcType);
|
||||
/*
|
||||
Expect.equals("function result", error.dstName);
|
||||
int pos = error.url.lastIndexOf("/", error.url.length);
|
||||
if (pos == -1) {
|
||||
pos = error.url.lastIndexOf("\\", error.url.length);
|
||||
}
|
||||
String subs = error.url.substring(pos + 1, error.url.length);
|
||||
Expect.equals("TypeTest.dart", subs);
|
||||
Expect.equals(472, error.line);
|
||||
Expect.equals(12, error.column);
|
||||
*/
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static int testListAssigment() {
|
||||
int result = 0;
|
||||
{
|
||||
var a = new List(5);
|
||||
List a0 = a;
|
||||
List<Object> ao = a;
|
||||
List<int> ai = a;
|
||||
List<num> an = a;
|
||||
List<String> as = a;
|
||||
}
|
||||
{
|
||||
var a = new List<Object>(5);
|
||||
List a0 = a;
|
||||
List<Object> ao = a;
|
||||
try {
|
||||
List<int> ai = a;
|
||||
} catch (TypeError error) {
|
||||
result++;
|
||||
}
|
||||
try {
|
||||
List<num> an = a;
|
||||
} catch (TypeError error) {
|
||||
result++;
|
||||
}
|
||||
try {
|
||||
List<String> as = a;
|
||||
} catch (TypeError error) {
|
||||
result++;
|
||||
}
|
||||
}
|
||||
{
|
||||
var a = new List<int>(5);
|
||||
List a0 = a;
|
||||
List<Object> ao = a;
|
||||
List<int> ai = a;
|
||||
List<num> an = a;
|
||||
try {
|
||||
List<String> as = a;
|
||||
} catch (TypeError error) {
|
||||
result++;
|
||||
}
|
||||
}
|
||||
{
|
||||
var a = new List<num>(5);
|
||||
List a0 = a;
|
||||
List<Object> ao = a;
|
||||
try {
|
||||
List<int> ai = a;
|
||||
} catch (TypeError error) {
|
||||
result++;
|
||||
}
|
||||
List<num> an = a;
|
||||
try {
|
||||
List<String> as = a;
|
||||
} catch (TypeError error) {
|
||||
result++;
|
||||
}
|
||||
}
|
||||
{
|
||||
var a = new List<String>(5);
|
||||
List a0 = a;
|
||||
List<Object> ao = a;
|
||||
try {
|
||||
List<int> ai = a;
|
||||
} catch (TypeError error) {
|
||||
result++;
|
||||
}
|
||||
try {
|
||||
List<num> an = a;
|
||||
} catch (TypeError error) {
|
||||
result++;
|
||||
}
|
||||
List<String> as = a;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static testMain() {
|
||||
Expect.equals(1, test());
|
||||
Expect.equals(1, testSideEffect());
|
||||
Expect.equals(1, testArgument());
|
||||
Expect.equals(1, testReturn());
|
||||
Expect.equals(1, testField());
|
||||
Expect.equals(1, testAnyFunction());
|
||||
//Expect.equals(1, testVoidFunction()); - Function type checking issue
|
||||
//Expect.equals(1, testFunctionNum()); - Function type checking issue
|
||||
//Expect.equals(9, testBoolCheck()); - Boolean checking on conditions is not done
|
||||
//Expect.equals(1, testFactory()); - Not doing a test on factories
|
||||
Expect.equals(8, testListAssigment());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class C {
|
||||
factory C() {
|
||||
return 1; // Implicit result type is 'C', not int.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
main() {
|
||||
TypeTest.testMain();
|
||||
}
|
Loading…
Reference in a new issue