Skip to content

Commit

Permalink
fix #25573, add option to disable implicit dynamic
Browse files Browse the repository at this point in the history
R=leafp@google.com

Review URL: https://codereview.chromium.org/2093523002 .
  • Loading branch information
John Messerly committed Jun 27, 2016
1 parent 4bae18a commit 844c82b
Show file tree
Hide file tree
Showing 7 changed files with 518 additions and 14 deletions.
4 changes: 4 additions & 0 deletions pkg/analyzer/lib/src/context/context.dart
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,9 @@ class AnalysisContextImpl implements InternalAnalysisContext {
((options is AnalysisOptionsImpl)
? this._options.implicitCasts != options.implicitCasts
: false) ||
((options is AnalysisOptionsImpl)
? this._options.implicitDynamic != options.implicitDynamic
: false) ||
this._options.enableStrictCallChecks !=
options.enableStrictCallChecks ||
this._options.enableGenericMethods != options.enableGenericMethods ||
Expand Down Expand Up @@ -313,6 +316,7 @@ class AnalysisContextImpl implements InternalAnalysisContext {
if (options is AnalysisOptionsImpl) {
this._options.strongModeHints = options.strongModeHints;
this._options.implicitCasts = options.implicitCasts;
this._options.implicitDynamic = options.implicitDynamic;
}
if (needsRecompute) {
for (WorkManager workManager in workManagers) {
Expand Down
33 changes: 33 additions & 0 deletions pkg/analyzer/lib/src/dart/element/type.dart
Original file line number Diff line number Diff line change
Expand Up @@ -926,6 +926,39 @@ class FunctionTypeImpl extends TypeImpl implements FunctionType {
}
}

/**
* Given a generic function type [g] and an instantiated function type [f],
* find a list of type arguments TArgs such that `g<TArgs> == f`,
* and return TArgs.
*
* This function must be called with type [f] that was instantiated from [g].
*/
static Iterable<DartType> recoverTypeArguments(
FunctionType g, FunctionType f) {
// TODO(jmesserly): perhaps a better design here would be: instead of
// recording staticInvokeType on InvocationExpression, we could record the
// instantiated type arguments, that way we wouldn't need to recover them.
//
// For now though, this is a pretty quick operation.
assert(identical(g.element, f.element));
assert(g.typeFormals.isNotEmpty && f.typeFormals.isEmpty);
assert(g.typeFormals.length + g.typeArguments.length ==
f.typeArguments.length);

// Instantiation in Analyzer works like this:
// Given:
// {U/T} <S> T -> S
// Where {U/T} represents the typeArguments (U) and typeParameters (T) list,
// and <S> represents the typeFormals.
//
// Now instantiate([V]), and the result should be:
// {U/T, V/S} T -> S.
//
// Therefore, we can recover the typeArguments from our instantiated
// function.
return f.typeArguments.skip(g.typeArguments.length);
}

/**
* Compares two function types [t] and [s] to see if their corresponding
* parameter types match [parameterRelation] and their return types match
Expand Down
13 changes: 13 additions & 0 deletions pkg/analyzer/lib/src/generated/engine.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1314,6 +1314,18 @@ class AnalysisOptionsImpl implements AnalysisOptions {
@override
bool finerGrainedInvalidation = false;

/**
* A flag indicating whether implicit dynamic type is allowed, on by default.
*
* This flag can be used without necessarily enabling [strongMode], but it is
* designed with strong mode's type inference in mind. Without type inference,
* it will raise many errors. Also it does not provide type safety without
* strong mode.
*
* This option is experimental and subject to change.
*/
bool implicitDynamic = true;

/**
* Initialize a newly created set of analysis options to have their default
* values.
Expand Down Expand Up @@ -1346,6 +1358,7 @@ class AnalysisOptionsImpl implements AnalysisOptions {
if (options is AnalysisOptionsImpl) {
strongModeHints = options.strongModeHints;
implicitCasts = options.implicitCasts;
implicitDynamic = options.implicitDynamic;
}
trackCacheDependencies = options.trackCacheDependencies;
finerGrainedInvalidation = options.finerGrainedInvalidation;
Expand Down
78 changes: 78 additions & 0 deletions pkg/analyzer/lib/src/generated/error.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2859,6 +2859,16 @@ abstract class ErrorCode {
StrongModeCode.DOWN_CAST_IMPLICIT,
StrongModeCode.DYNAMIC_CAST,
StrongModeCode.DYNAMIC_INVOKE,
StrongModeCode.IMPLICIT_DYNAMIC_FIELD,
StrongModeCode.IMPLICIT_DYNAMIC_FUNCTION,
StrongModeCode.IMPLICIT_DYNAMIC_INVOKE,
StrongModeCode.IMPLICIT_DYNAMIC_LIST_LITERAL,
StrongModeCode.IMPLICIT_DYNAMIC_MAP_LITERAL,
StrongModeCode.IMPLICIT_DYNAMIC_METHOD,
StrongModeCode.IMPLICIT_DYNAMIC_PARAMETER,
StrongModeCode.IMPLICIT_DYNAMIC_RETURN,
StrongModeCode.IMPLICIT_DYNAMIC_TYPE,
StrongModeCode.IMPLICIT_DYNAMIC_VARIABLE,
StrongModeCode.INFERRED_TYPE,
StrongModeCode.INFERRED_TYPE_ALLOCATION,
StrongModeCode.INFERRED_TYPE_CLOSURE,
Expand Down Expand Up @@ -5874,6 +5884,17 @@ class StrongModeCode extends ErrorCode {
'The type of {0}.{1} ({2}) is not a '
'subtype of {3}.{1} ({4}).';

/**
* This is appended to the end of an error message about implicit dynamic.
*
* The idea is to make sure the user is aware that this error message is the
* result of turning on a particular option, and they are free to turn it
* back off.
*/
static const String _implicitDynamicTip =
". Either add an explicit type like 'dynamic'"
", or enable implicit-dynamic in your Analyzer options.";

static const String _inferredTypeMessage = '{0} has inferred type {1}';

static const StrongModeCode DOWN_CAST_COMPOSITE = const StrongModeCode(
Expand Down Expand Up @@ -5947,6 +5968,63 @@ class StrongModeCode extends ErrorCode {
'Field declaration {3}.{1} cannot be '
'overridden in {0}.');

static const StrongModeCode IMPLICIT_DYNAMIC_PARAMETER = const StrongModeCode(
ErrorType.COMPILE_TIME_ERROR,
'IMPLICIT_DYNAMIC_PARAMETER',
"Missing parameter type for '{0}'$_implicitDynamicTip");

static const StrongModeCode IMPLICIT_DYNAMIC_RETURN = const StrongModeCode(
ErrorType.COMPILE_TIME_ERROR,
'IMPLICIT_DYNAMIC_RETURN',
"Missing return type for '{0}'$_implicitDynamicTip");

static const StrongModeCode IMPLICIT_DYNAMIC_VARIABLE = const StrongModeCode(
ErrorType.COMPILE_TIME_ERROR,
'IMPLICIT_DYNAMIC_VARIABLE',
"Missing variable type for '{0}'$_implicitDynamicTip");

static const StrongModeCode IMPLICIT_DYNAMIC_FIELD = const StrongModeCode(
ErrorType.COMPILE_TIME_ERROR,
'IMPLICIT_DYNAMIC_FIELD',
"Missing field type for '{0}'$_implicitDynamicTip");

static const StrongModeCode IMPLICIT_DYNAMIC_TYPE =
const StrongModeCode(
ErrorType.COMPILE_TIME_ERROR,
'IMPLICIT_DYNAMIC_TYPE',
"Missing type arguments for generic type '{0}'"
"$_implicitDynamicTip");

static const StrongModeCode IMPLICIT_DYNAMIC_LIST_LITERAL =
const StrongModeCode(
ErrorType.COMPILE_TIME_ERROR,
'IMPLICIT_DYNAMIC_LIST_LITERAL',
"Missing type argument for list literal$_implicitDynamicTip");

static const StrongModeCode IMPLICIT_DYNAMIC_MAP_LITERAL =
const StrongModeCode(
ErrorType.COMPILE_TIME_ERROR,
'IMPLICIT_DYNAMIC_MAP_LITERAL',
'Missing type arguments for map literal$_implicitDynamicTip');

static const StrongModeCode IMPLICIT_DYNAMIC_FUNCTION = const StrongModeCode(
ErrorType.COMPILE_TIME_ERROR,
'IMPLICIT_DYNAMIC_FUNCTION',
"Missing type arguments for generic function '{0}<{1}>'"
"$_implicitDynamicTip");

static const StrongModeCode IMPLICIT_DYNAMIC_METHOD = const StrongModeCode(
ErrorType.COMPILE_TIME_ERROR,
'IMPLICIT_DYNAMIC_METHOD',
"Missing type arguments for generic method '{0}<{1}>'"
"$_implicitDynamicTip");

static const StrongModeCode IMPLICIT_DYNAMIC_INVOKE = const StrongModeCode(
ErrorType.COMPILE_TIME_ERROR,
'IMPLICIT_DYNAMIC_INVOKE',
"Missing type arguments for calling generic function type '{0}'"
"$_implicitDynamicTip");

@override
final ErrorType type;

Expand Down
Loading

0 comments on commit 844c82b

Please sign in to comment.