[cfe] Support nnbd platform without experiment enabled

All handling of the opt-out features were guarded by the experimental flag.
With this CL the opt-out semantics is used irregardless of the
the experimental flag. This supports compiling with opt-out semantics
against libraries which have been compiled with the flag enabled, as will
be the case when the nnbd sdk is unforked.

Closes #40334

Change-Id: I2df5c700f97844bdd3e33bccba7e72013f0c831e
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/133780
Reviewed-by: Dmitry Stefantsov <dmitryas@google.com>
Commit-Queue: Johnni Winther <johnniwinther@google.com>
This commit is contained in:
Johnni Winther 2020-01-30 12:56:26 +00:00 committed by commit-bot@chromium.org
parent e1e0ae5898
commit 7248e98023
6 changed files with 119 additions and 100 deletions

View file

@ -6,8 +6,35 @@
// @dart=2.6
/*class: Class:Class,Object*/
class Class {
/*member: Class.==:bool! Function(dynamic)**/
/*class: Class1:Class1,Object*/
class Class1 {
/*member: Class1.==:bool! Function(dynamic)**/
operator ==(other) => true;
}
/*class: Class2a:Class2a,Object*/
abstract class Class2a {
/*member: Class2a.==:bool* Function(Object*)**/
bool operator ==(Object other);
}
/*class: Class2b:Class2a,Class2b,Object*/
class Class2b extends Class2a {
/*member: Class2b.==:bool* Function(Object*)**/
}
/*class: Class3a:Class3a,Object*/
class Class3a {
/*member: Class3a.==:bool* Function(Object*)**/
}
/*class: Class3b:Class3a,Class3b,Object*/
abstract class Class3b extends Class3a {
/*member: Class3b.==:bool* Function(Object*)**/
bool operator ==(Object other);
}
/*class: Class3c:Class3a,Class3b,Class3c,Object*/
class Class3c extends Class3b {
/*member: Class3c.==:bool* Function(Object*)**/
}

View file

@ -375,11 +375,9 @@ class SourceFieldBuilder extends MemberBuilderImpl implements FieldBuilder {
if (fieldType is ImplicitFieldType) {
// `fieldType` may have changed if a circularity was detected when
// [inferredType] was computed.
if (library.loader.target.enableNonNullable) {
if (!library.isNonNullableByDefault) {
inferredType = legacyErasure(
library.loader.typeInferenceEngine.coreTypes, inferredType);
}
if (!library.isNonNullableByDefault) {
inferredType = legacyErasure(
library.loader.typeInferenceEngine.coreTypes, inferredType);
}
fieldType = inferredType;

View file

@ -142,6 +142,16 @@ abstract class MemberBuilderImpl extends ModifierBuilderImpl
@override
String get fullNameForErrors => name;
@override
StringBuffer printOn(StringBuffer buffer) {
if (isClassMember) {
buffer.write(classBuilder.name);
buffer.write('.');
}
buffer.write(name);
return buffer;
}
@override
ClassBuilder get classBuilder => parent is ClassBuilder ? parent : null;
}

View file

@ -240,9 +240,8 @@ class ClassHierarchyBuilder {
}
ClassHierarchyNode getNodeFromClassBuilder(ClassBuilder classBuilder) {
return nodes[classBuilder.cls] ??= new ClassHierarchyNodeBuilder(
this, classBuilder, loader.target.enableNonNullable)
.build();
return nodes[classBuilder.cls] ??=
new ClassHierarchyNodeBuilder(this, classBuilder).build();
}
ClassHierarchyNode getNodeFromTypeBuilder(TypeBuilder type) {
@ -409,9 +408,8 @@ class ClassHierarchyBuilder {
for (int i = 0; i < classes.length; i++) {
ClassBuilder classBuilder = classes[i];
if (!classBuilder.isPatch) {
hierarchy.nodes[classBuilder.cls] = new ClassHierarchyNodeBuilder(
hierarchy, classBuilder, loader.target.enableNonNullable)
.build();
hierarchy.nodes[classBuilder.cls] =
new ClassHierarchyNodeBuilder(hierarchy, classBuilder).build();
} else {
// TODO(ahe): Merge the injected members of patch into the hierarchy
// node of `cls.origin`.
@ -426,15 +424,11 @@ class ClassHierarchyNodeBuilder {
final ClassBuilder classBuilder;
/// Whether non-nullable types are supported.
final bool enableNonNullable;
bool hasNoSuchMethod = false;
List<ClassMember> abstractMembers = null;
ClassHierarchyNodeBuilder(
this.hierarchy, this.classBuilder, this.enableNonNullable);
ClassHierarchyNodeBuilder(this.hierarchy, this.classBuilder);
ClassBuilder get objectClass => hierarchy.objectClassBuilder;
@ -736,7 +730,8 @@ class ClassHierarchyNodeBuilder {
if (substitution != null) {
bType = substitution.substituteType(bType);
}
if (enableNonNullable &&
if (hierarchy
.coreTypes.objectClass.enclosingLibrary.isNonNullableByDefault &&
!a.classBuilder.library.isNonNullableByDefault &&
b.member == hierarchy.coreTypes.objectEquals) {
// In legacy code we special case `Object.==` to infer `dynamic` instead
@ -1184,13 +1179,13 @@ class ClassHierarchyNodeBuilder {
member = delayedMember.withParent(classBuilder);
hierarchy.delayedMemberChecks.add(member);
}
if (mergeKind.intoCurrentClass &&
hierarchy.loader.target.enableNonNullable) {
if (mergeKind.intoCurrentClass) {
if (member.classBuilder.library.isNonNullableByDefault &&
!classBuilder.library.isNonNullableByDefault) {
if (member is! DelayedMember) {
member = new InterfaceConflict(
classBuilder, [member], mergeKind.forSetters, shouldModifyKernel);
classBuilder, [member], mergeKind.forSetters, shouldModifyKernel,
isAbstract: isAbstract(member));
hierarchy.delayedMemberChecks.add(member);
}
}
@ -1506,8 +1501,7 @@ class ClassHierarchyNodeBuilder {
DartType addInterface(
List<DartType> interfaces, List<DartType> superclasses, DartType type) {
if (hierarchy.loader.target.enableNonNullable &&
!classBuilder.library.isNonNullableByDefault) {
if (!classBuilder.library.isNonNullableByDefault) {
type = legacyErasure(hierarchy.coreTypes, type);
}
if (type is InterfaceType) {
@ -1518,18 +1512,16 @@ class ClassHierarchyNodeBuilder {
DartType superclass = depth < myDepth ? superclasses[depth] : null;
if (superclass is InterfaceType &&
superclass.classNode == type.classNode) {
if (hierarchy.loader.target.enableNonNullable) {
// This is a potential conflict.
if (classBuilder.library.isNonNullableByDefault) {
superclass = nnbdTopMerge(hierarchy.coreTypes, superclass, type);
if (superclass == null) {
// This is a conflict.
// TODO(johnniwinther): Report errors here instead of through
// the computation of the [ClassHierarchy].
superclass = superclasses[depth];
} else {
superclasses[depth] = superclass;
}
// This is a potential conflict.
if (classBuilder.library.isNonNullableByDefault) {
superclass = nnbdTopMerge(hierarchy.coreTypes, superclass, type);
if (superclass == null) {
// This is a conflict.
// TODO(johnniwinther): Report errors here instead of through
// the computation of the [ClassHierarchy].
superclass = superclasses[depth];
} else {
superclasses[depth] = superclass;
}
}
return superclass;
@ -1540,18 +1532,16 @@ class ClassHierarchyNodeBuilder {
DartType interface = interfaces[i];
if (interface is InterfaceType &&
interface.classNode == type.classNode) {
if (hierarchy.loader.target.enableNonNullable) {
// This is a potential conflict.
if (classBuilder.library.isNonNullableByDefault) {
interface = nnbdTopMerge(hierarchy.coreTypes, interface, type);
if (interface == null) {
// This is a conflict.
// TODO(johnniwinther): Report errors here instead of through
// the computation of the [ClassHierarchy].
interface = interfaces[i];
} else {
interfaces[i] = interface;
}
// This is a potential conflict.
if (classBuilder.library.isNonNullableByDefault) {
interface = nnbdTopMerge(hierarchy.coreTypes, interface, type);
if (interface == null) {
// This is a conflict.
// TODO(johnniwinther): Report errors here instead of through
// the computation of the [ClassHierarchy].
interface = interfaces[i];
} else {
interfaces[i] = interface;
}
}
return interface;
@ -2469,8 +2459,11 @@ class InheritedImplementationInterfaceConflict extends DelayedMember {
}
class InterfaceConflict extends DelayedMember {
bool isAbstract;
InterfaceConflict(ClassBuilder parent, List<ClassMember> declarations,
bool isSetter, bool modifyKernel)
bool isSetter, bool modifyKernel,
{this.isAbstract: true})
: super(parent, declarations, isSetter, modifyKernel);
Member combinedMemberSignatureResult;
@ -2717,6 +2710,8 @@ class AbstractMemberOverridingImplementation extends DelayedMember {
static ClassMember selectConcrete(ClassMember declaration) {
if (declaration is AbstractMemberOverridingImplementation) {
return declaration.concreteImplementation;
} else if (declaration is InterfaceConflict && !declaration.isAbstract) {
return selectConcrete(declaration.declarations.single);
} else {
return declaration;
}
@ -2758,7 +2753,8 @@ int compareNamedParameters(VariableDeclaration a, VariableDeclaration b) {
}
bool isAbstract(ClassMember declaration) {
return declaration.member.isAbstract || declaration is InterfaceConflict;
return declaration.member.isAbstract ||
(declaration is InterfaceConflict && declaration.isAbstract);
}
bool inferParameterType(

View file

@ -47,7 +47,7 @@ import 'class_hierarchy_builder.dart';
class ForwardingNode {
final ClassHierarchyBuilder hierarchy;
final SourceClassBuilder parent;
final SourceClassBuilder classBuilder;
final ClassMember combinedMemberSignatureResult;
@ -57,12 +57,12 @@ class ForwardingNode {
/// procedures of the class in question.
final List<ClassMember> _candidates;
ForwardingNode(this.hierarchy, this.parent,
ForwardingNode(this.hierarchy, this.classBuilder,
this.combinedMemberSignatureResult, this._candidates, this.kind);
Name get name => combinedMemberSignatureResult.member.name;
Class get enclosingClass => parent.cls;
Class get enclosingClass => classBuilder.cls;
/// Finishes handling of this node by propagating covariance and creating
/// forwarding stubs if necessary.
@ -169,12 +169,9 @@ class ForwardingNode {
bool needsCheck(DartType type) => needsCheckVisitor == null
? false
: substitution.substituteType(type).accept(needsCheckVisitor);
bool enableNonNullable = hierarchy.loader.target.enableNonNullable;
bool isNonNullableByDefault =
enableNonNullable && parent.library.isNonNullableByDefault;
bool isNonNullableByDefault = classBuilder.library.isNonNullableByDefault;
DartType initialType(DartType a) {
if (!enableNonNullable) return null;
if (!isNonNullableByDefault) {
a = legacyErasure(hierarchy.coreTypes, a);
}
@ -191,8 +188,8 @@ class ForwardingNode {
for (int i = 0; i < interfacePositionalParameters.length; i++) {
VariableDeclaration parameter = interfacePositionalParameters[i];
DartType parameterType = parameter.type;
DartType type = initialType(substitution.substituteType(parameterType));
DartType parameterType = substitution.substituteType(parameter.type);
DartType type = initialType(parameterType);
bool isGenericCovariantImpl =
parameter.isGenericCovariantImpl || needsCheck(parameter.type);
bool isCovariant = parameter.isCovariant;
@ -232,19 +229,17 @@ class ForwardingNode {
stub.function.positionalParameters[i].isCovariant = true;
}
}
if (enableNonNullable) {
if (type != null && type != parameterType) {
// TODO(johnniwinther): Report an error when [type] is null; this
// means that nnbd-top-merge was not defined.
createStubIfNeeded(forMemberSignature: true);
stub.function.positionalParameters[i].type = type;
}
if (type != null && type != parameterType) {
// TODO(johnniwinther): Report an error when [type] is null; this
// means that nnbd-top-merge was not defined.
createStubIfNeeded(forMemberSignature: true);
stub.function.positionalParameters[i].type = type;
}
}
for (int i = 0; i < interfaceNamedParameters.length; i++) {
VariableDeclaration parameter = interfaceNamedParameters[i];
DartType parameterType = parameter.type;
DartType type = initialType(substitution.substituteType(parameterType));
DartType parameterType = substitution.substituteType(parameter.type);
DartType type = initialType(parameterType);
bool isGenericCovariantImpl =
parameter.isGenericCovariantImpl || needsCheck(parameter.type);
bool isCovariant = parameter.isCovariant;
@ -284,13 +279,11 @@ class ForwardingNode {
stub.function.namedParameters[i].isCovariant = true;
}
}
if (enableNonNullable) {
if (type != null && type != parameterType) {
// TODO(johnniwinther): Report an error when [type] is null; this
// means that nnbd-top-merge was not defined.
createStubIfNeeded(forMemberSignature: true);
stub.function.namedParameters[i].type = type;
}
if (type != null && type != parameterType) {
// TODO(johnniwinther): Report an error when [type] is null; this
// means that nnbd-top-merge was not defined.
createStubIfNeeded(forMemberSignature: true);
stub.function.namedParameters[i].type = type;
}
}
for (int i = 0; i < interfaceTypeParameters.length; i++) {
@ -321,21 +314,19 @@ class ForwardingNode {
}
}
}
if (enableNonNullable) {
DartType returnType =
substitution.substituteType(getReturnType(interfaceMember));
DartType type = initialType(returnType);
for (int j = 0; j < _candidates.length; j++) {
Member otherMember = getCandidateAt(j);
type = mergeTypes(
type, substitutions[j].substituteType(getReturnType(otherMember)));
}
if (type != null && type != returnType) {
// TODO(johnniwinther): Report an error when [type] is null; this
// means that nnbd-top-merge was not defined.
createStubIfNeeded(forMemberSignature: true);
stub.function.returnType = type;
}
DartType returnType =
substitution.substituteType(getReturnType(interfaceMember));
DartType type = initialType(returnType);
for (int j = 0; j < _candidates.length; j++) {
Member otherMember = getCandidateAt(j);
type = mergeTypes(
type, substitutions[j].substituteType(getReturnType(otherMember)));
}
if (type != null && type != returnType) {
// TODO(johnniwinther): Report an error when [type] is null; this
// means that nnbd-top-merge was not defined.
createStubIfNeeded(forMemberSignature: true);
stub.function.returnType = type;
}
return stub;
}
@ -447,13 +438,13 @@ class ForwardingNode {
finalTarget = target;
}
Procedure referenceFrom;
if (parent.referencesFromIndexed != null) {
if (classBuilder.referencesFromIndexed != null) {
if (kind == ProcedureKind.Setter) {
referenceFrom =
parent.referencesFromIndexed.lookupProcedureSetter(name.name);
classBuilder.referencesFromIndexed.lookupProcedureSetter(name.name);
} else {
referenceFrom =
parent.referencesFromIndexed.lookupProcedureNotSetter(name.name);
referenceFrom = classBuilder.referencesFromIndexed
.lookupProcedureNotSetter(name.name);
}
}
return new Procedure(name, kind, function,

View file

@ -106,11 +106,8 @@ class _ImplicitFieldTypeAlias extends ImplicitFieldType {
DartType inferType() {
DartType type = _root.inferType();
if (_targetFieldBuilder.library.loader.target.enableNonNullable) {
if (!_targetFieldBuilder.library.isNonNullableByDefault) {
type =
legacyErasure(_targetFieldBuilder.library.loader.coreTypes, type);
}
if (!_targetFieldBuilder.library.isNonNullableByDefault) {
type = legacyErasure(_targetFieldBuilder.library.loader.coreTypes, type);
}
return _targetFieldBuilder.fieldType = type;
}