[dartdevc] Fix nullability of function types and typedefs
These fixes also prepare for an upcoming change to normalize FutureOr
types.
- Cache and emit the hoisted function type at the top level without
nullability wrappers.
- Always emit nullability wrappers at the use site.
- Fix issue where sometimes the return type would be double wrapped.
Change-Id: If4a0c94e62eca626f271cc3c259c813911075d9a
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/136404
Reviewed-by: Mark Zhou <markzipan@google.com>
Reviewed-by: Sigmund Cherem <sigmund@google.com>
Commit-Queue: Nicholas Shahan <nshahan@google.com>
diff --git a/pkg/dev_compiler/lib/src/kernel/compiler.dart b/pkg/dev_compiler/lib/src/kernel/compiler.dart
index fbd18ba..41ef67c 100644
--- a/pkg/dev_compiler/lib/src/kernel/compiler.dart
+++ b/pkg/dev_compiler/lib/src/kernel/compiler.dart
@@ -1375,7 +1375,8 @@
FunctionType result;
if (!f.positionalParameters.any(isCovariantParameter) &&
!f.namedParameters.any(isCovariantParameter)) {
- result = f.computeThisFunctionType(member.enclosingLibrary.nonNullable);
+ // Avoid tagging a member as Function? or Function*
+ result = f.computeThisFunctionType(Nullability.nonNullable);
} else {
DartType reifyParameter(VariableDeclaration p) => isCovariantParameter(p)
? _coreTypes.objectRawType(member.enclosingLibrary.nullable)
@@ -1386,7 +1387,7 @@
// TODO(jmesserly): do covariant type parameter bounds also need to be
// reified as `Object`?
result = FunctionType(f.positionalParameters.map(reifyParameter).toList(),
- f.returnType, Nullability.legacy,
+ f.returnType, Nullability.nonNullable,
namedParameters: f.namedParameters.map(reifyNamedParameter).toList()
..sort(),
typeParameters: f
@@ -2543,7 +2544,10 @@
js_ast.Expression _emitFunctionTagged(js_ast.Expression fn, FunctionType type,
{bool topLevel = false}) {
var lazy = topLevel && !_canEmitTypeAtTopLevel(type);
- var typeRep = visitFunctionType(type, lazy: lazy);
+ var typeRep = visitFunctionType(
+ // Avoid tagging a closure as Function? or Function*
+ type.withNullability(Nullability.nonNullable),
+ lazy: lazy);
return runtimeCall(lazy ? 'lazyFn(#, #)' : 'fn(#, #)', [fn, typeRep]);
}
@@ -2743,14 +2747,12 @@
: namedTypes.add(param));
var allNamedTypes = type.namedParameters;
- var returnType = _emitNullabilityWrapper(
- _emitType(type.returnType), type.returnType.nullability);
+ var returnType = _emitType(type.returnType);
var requiredArgs = _emitTypeNames(requiredTypes, requiredParams, member);
List<js_ast.Expression> typeParts;
if (allNamedTypes.isNotEmpty) {
assert(optionalTypes.isEmpty);
- // TODO(vsm): The old pageloader may require annotations here.
var namedArgs = _emitTypeProperties(namedTypes);
var requiredNamedArgs = _emitTypeProperties(requiredNamedTypes);
typeParts = [returnType, requiredArgs, namedArgs, requiredNamedArgs];
@@ -2816,9 +2818,13 @@
helperCall = 'fnType(#)';
}
var typeRep = runtimeCall(helperCall, [typeParts]);
- return _cacheTypes
+ // Avoid caching the nullability of the function type itself so it can be
+ // shared by nullable, non-nullable, and legacy versions at the use site.
+ typeRep = _cacheTypes
? _typeTable.nameFunctionType(type, typeRep, lazy: lazy)
: typeRep;
+
+ return _emitNullabilityWrapper(typeRep, type.nullability);
}
js_ast.Expression _emitAnnotatedFunctionType(
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/types.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/types.dart
index a69f6fe..ed0e58a 100644
--- a/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/types.dart
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/types.dart
@@ -757,7 +757,6 @@
@JSExportName('as')
as_T(obj, [@notNull bool isImplicit = false]) {
- if (obj == null) return obj;
if (JS('!', 'typeof # == "function"', obj)) {
var actual = JS('', '#[#]', obj, _runtimeType);
// If there's no actual type, it's a JS function.
@@ -981,13 +980,13 @@
@JSExportName('as')
as_T(obj) {
- if (obj == null || is_T(obj)) return obj;
+ if (is_T(obj)) return obj;
return castError(obj, this, false);
}
@JSExportName('_check')
check_T(obj) {
- if (obj == null || is_T(obj)) return obj;
+ if (is_T(obj)) return obj;
return castError(obj, this, true);
}
}