diff --git a/pkg/front_end/lib/src/fragment/constructor/encoding.dart b/pkg/front_end/lib/src/fragment/constructor/encoding.dart index 06ee54919e7..c53caadfdf0 100644 --- a/pkg/front_end/lib/src/fragment/constructor/encoding.dart +++ b/pkg/front_end/lib/src/fragment/constructor/encoding.dart @@ -122,6 +122,8 @@ class RegularConstructorEncoding implements ConstructorEncoding { Statement? bodyInternal; + List? _prependedInitializers; + RegularConstructorEncoding({ required bool isExternal, required bool isEnumConstructor, @@ -363,12 +365,17 @@ class RegularConstructorEncoding implements ConstructorEncoding { // compile), and so we also clear them. // Note: this method clears both initializers from the target Kernel node // and internal state associated with parsing initializers. - _constructor.initializers = []; + if (_prependedInitializers != null) { + _constructor.initializers = [..._prependedInitializers!.reversed]; + } else { + _constructor.initializers = []; + } } @override void prependInitializer(Initializer initializer) { initializer.parent = _constructor; + (_prependedInitializers ??= []).add(initializer); _constructor.initializers.insert(0, initializer); } @@ -477,6 +484,8 @@ mixin _ExtensionTypeConstructorEncodingMixin Statement? bodyInternal; + List? _prependedInitializers; + /// If this procedure is an extension instance member or extension type /// instance member, [_thisVariable] holds the synthetically added `this` /// parameter. @@ -691,15 +700,17 @@ mixin _ExtensionTypeConstructorEncodingMixin // compile), and so we also clear them. // Note: this method clears both initializers from the target Kernel node // and internal state associated with parsing initializers. - _initializers = []; - // TODO(johnniwinther): Can these be moved here from the - // [SourceConstructorBuilder]? - //redirectingInitializer = null; - //superInitializer = null; + if (_prependedInitializers != null) { + // Coverage-ignore-block(suite): Not run. + _initializers = [..._prependedInitializers!.reversed]; + } else { + _initializers = []; + } } @override void prependInitializer(Initializer initializer) { + (_prependedInitializers ??= []).add(initializer); _initializers.insert(0, initializer); } diff --git a/pkg/front_end/lib/src/fragment/enum_element.dart b/pkg/front_end/lib/src/fragment/enum_element.dart index 2a9c2a38127..6deda5e9561 100644 --- a/pkg/front_end/lib/src/fragment/enum_element.dart +++ b/pkg/front_end/lib/src/fragment/enum_element.dart @@ -117,7 +117,7 @@ class EnumElementDeclaration required DeclarationBuilder? declarationBuilder, required List annotatables, required Uri annotatablesFileUri, - required bool isClassInstanceMember, + required bool forConstantConstructor, }) { BodyBuilderContext bodyBuilderContext = createBodyBuilderContext(); for (Annotatable annotatable in annotatables) { diff --git a/pkg/front_end/lib/src/fragment/field.dart b/pkg/front_end/lib/src/fragment/field.dart index 115fa9226d3..63b185cc67c 100644 --- a/pkg/front_end/lib/src/fragment/field.dart +++ b/pkg/front_end/lib/src/fragment/field.dart @@ -14,8 +14,8 @@ class FieldFragment implements Fragment { final int endOffset; - Token? _initializerToken; - Token? _constInitializerToken; + Token? _initializerTokenForTopLevelInference; + Token? _initializerTokenForOutline; final List? metadata; @@ -45,7 +45,6 @@ class FieldFragment implements Fragment { required this.nameOffset, required this.endOffset, required Token? initializerToken, - required Token? constInitializerToken, required this.metadata, required this.type, required this.isTopLevel, @@ -53,8 +52,8 @@ class FieldFragment implements Fragment { required this.enclosingScope, required this.enclosingDeclaration, required this.enclosingCompilationUnit, - }) : _initializerToken = initializerToken, - _constInitializerToken = constInitializerToken; + }) : _initializerTokenForTopLevelInference = initializerToken, + _initializerTokenForOutline = initializerToken; @override SourcePropertyBuilder get builder { @@ -73,10 +72,10 @@ class FieldFragment implements Fragment { /// /// This can only be called once and will hand over the responsibility of /// the token to the caller. - Token? takeConstInitializerToken() { - Token? result = _constInitializerToken; + Token? takeInitializerTokenForOutline() { + Token? result = _initializerTokenForOutline; // Ensure that we don't hold onto the token. - _constInitializerToken = null; + _initializerTokenForOutline = null; return result; } @@ -114,10 +113,10 @@ class FieldFragment implements Fragment { /// /// This can only be called once and will hand over the responsibility of /// the token to the caller. - Token? takeInitializerToken() { - Token? result = _initializerToken; + Token? takeInitializerTokenForTopLevelInference() { + Token? result = _initializerTokenForTopLevelInference; // Ensure that we don't hold on to the token. - _initializerToken = null; + _initializerTokenForTopLevelInference = null; return result; } diff --git a/pkg/front_end/lib/src/fragment/field/body_builder_context.dart b/pkg/front_end/lib/src/fragment/field/body_builder_context.dart index a5efbdf8ce7..dd239492ca6 100644 --- a/pkg/front_end/lib/src/fragment/field/body_builder_context.dart +++ b/pkg/front_end/lib/src/fragment/field/body_builder_context.dart @@ -41,6 +41,17 @@ class FieldFragmentBodyBuilderContext extends BodyBuilderContext { isDeclarationInstanceMember: _builder.isDeclarationInstanceMember, ); + @override + bool get inPrimaryConstructorFieldInitializer { + DeclarationBuilder? declarationBuilder = _builder.declarationBuilder; + if (declarationBuilder is SourceClassBuilder && + !_declaration.isStatic && + !isLateField) { + return declarationBuilder.hasPrimaryConstructor; + } + return false; + } + @override List? get primaryConstructorInitializerScopeParameters { diff --git a/pkg/front_end/lib/src/fragment/field/declaration.dart b/pkg/front_end/lib/src/fragment/field/declaration.dart index cba3bf9e4f6..48341a1966e 100644 --- a/pkg/front_end/lib/src/fragment/field/declaration.dart +++ b/pkg/front_end/lib/src/fragment/field/declaration.dart @@ -67,7 +67,7 @@ abstract class FieldDeclaration { required DeclarationBuilder? declarationBuilder, required List annotatables, required Uri annotatablesFileUri, - required bool isClassInstanceMember, + required bool forConstantConstructor, }); int computeFieldDefaultTypes(ComputeDefaultTypeContext context); @@ -334,7 +334,7 @@ class RegularFieldDeclaration required DeclarationBuilder? declarationBuilder, required List annotatables, required Uri annotatablesFileUri, - required bool isClassInstanceMember, + required bool forConstantConstructor, }) { BodyBuilderContext bodyBuilderContext = createBodyBuilderContext(); for (Annotatable annotatable in annotatables) { @@ -352,13 +352,9 @@ class RegularFieldDeclaration // For modular compilation we need to include initializers of all const // fields and all non-static final fields in classes with const constructors // into the outline. - Token? token = _fragment.takeConstInitializerToken(); + Token? token = _fragment.takeInitializerTokenForOutline(); if (!hasBodyBeenBuilt && token != null) { - if ((_fragment.modifiers.isConst || - (isFinal && - isClassInstanceMember && - (declarationBuilder as SourceClassBuilder) - .declaresConstConstructor))) { + if (_fragment.modifiers.isConst || forConstantConstructor) { if (hasInitializerBeenComputed) { buildBody(classHierarchy.coreTypes, cachedFieldInitializer); } else { @@ -587,7 +583,7 @@ class RegularFieldDeclaration } type.registerInferredTypeListener(this); - Token? token = _fragment.takeInitializerToken(); + Token? token = _fragment.takeInitializerTokenForTopLevelInference(); if (type is InferableTypeBuilder) { if (!_fragment.modifiers.hasInitializer && isStatic) { // A static field without type and initializer will always be inferred diff --git a/pkg/front_end/lib/src/fragment/primary_constructor_field.dart b/pkg/front_end/lib/src/fragment/primary_constructor_field.dart index c008cd52c67..7f155fe36a4 100644 --- a/pkg/front_end/lib/src/fragment/primary_constructor_field.dart +++ b/pkg/front_end/lib/src/fragment/primary_constructor_field.dart @@ -122,7 +122,7 @@ class PrimaryConstructorFieldDeclaration required DeclarationBuilder? declarationBuilder, required List annotatables, required Uri annotatablesFileUri, - required bool isClassInstanceMember, + required bool forConstantConstructor, }) { BodyBuilderContext bodyBuilderContext = createBodyBuilderContext(); for (Annotatable annotatable in annotatables) { diff --git a/pkg/front_end/lib/src/kernel/body_builder.dart b/pkg/front_end/lib/src/kernel/body_builder.dart index 55fbd63de2b..896182b5f49 100644 --- a/pkg/front_end/lib/src/kernel/body_builder.dart +++ b/pkg/front_end/lib/src/kernel/body_builder.dart @@ -1252,7 +1252,7 @@ class BodyBuilderImpl extends StackListenerImpl return _initializers; } - Expression parseFieldInitializer(Token token) { + Expression _parseInitializer(Token token) { Parser parser = new Parser( this, useImplicitCreationExpression: useImplicitCreationExpressionInCfe, @@ -1266,7 +1266,6 @@ class BodyBuilderImpl extends StackListenerImpl unionOfKinds([ValueKinds.Expression, ValueKinds.Generator]), ]), ); - //print(constantContext); Expression expression = popForValue(); checkEmpty(endToken.charOffset); return expression; @@ -2671,6 +2670,7 @@ class BodyBuilderImpl extends StackListenerImpl if (mustBeConst && !getable.isConst && !(_context.isConstructor && inFieldInitializer) && + !_context.inPrimaryConstructorFieldInitializer && !libraryFeatures.constFunctions.isEnabled) { return new IncompleteErrorGenerator( this, @@ -3432,12 +3432,13 @@ class BodyBuilderImpl extends StackListenerImpl push(variableInitialization); } - @override - void beginFieldInitializer(Token token) { - inFieldInitializer = true; - constantContext = _context.constantContext; - inLateFieldInitializer = _context.isLateField; - if (_context.isDeclarationInstanceContext && !inLateFieldInitializer) { + /// Sets up the local scope for a field initializer. + /// + /// For non-late instance fields the scope includes primary constructor + /// parameter. + void _enterFieldInitializerScope() { + if (_context.inPrimaryConstructorFieldInitializer) { + inConstructorInitializer = true; LocalScope enclosingScope = _localScope; List? parameters = _context.primaryConstructorInitializerScopeParameters; @@ -3457,6 +3458,22 @@ class BodyBuilderImpl extends StackListenerImpl _localScopes.push(enclosingScope); } } + } + + /// Pop the locals scope set up in [_enterFieldInitializerScope]. + void _exitFieldInitializerScope() { + if (_context.inPrimaryConstructorFieldInitializer) { + _localScopes.pop(); + inConstructorInitializer = false; + } + } + + @override + void beginFieldInitializer(Token token) { + inFieldInitializer = true; + constantContext = _context.constantContext; + inLateFieldInitializer = _context.isLateField; + _enterFieldInitializerScope(); if (_context.isAbstractField) { addProblem(diag.abstractFieldInitializer, token.charOffset, noLength); } else if (_context.isExternalField) { @@ -3467,13 +3484,11 @@ class BodyBuilderImpl extends StackListenerImpl @override void endFieldInitializer(Token assignmentOperator, Token endToken) { debugEvent("FieldInitializer"); - if (_context.isDeclarationInstanceContext && !inLateFieldInitializer) { - _localScopes.pop(); - } inFieldInitializer = false; inLateFieldInitializer = false; assert(assignmentOperator.stringValue == "="); push(popForValue()); + _exitFieldInitializerScope(); constantContext = ConstantContext.none; } @@ -11188,7 +11203,7 @@ class BodyBuilderImpl extends StackListenerImpl BuildParameterInitializerResult buildParameterInitializer({ required Token initializerToken, }) { - Expression initializer = parseFieldInitializer(initializerToken); + Expression initializer = _parseInitializer(initializerToken); return new BuildParameterInitializerResult( initializer, _takePendingAnnotations(), @@ -11448,7 +11463,9 @@ class BodyBuilderImpl extends StackListenerImpl }) { inFieldInitializer = true; inLateFieldInitializer = isLate; - Expression initializer = parseFieldInitializer(startToken); + _enterFieldInitializerScope(); + Expression initializer = _parseInitializer(startToken); + _exitFieldInitializerScope(); return new BuildFieldInitializerResult( initializer, _takePendingAnnotations(), diff --git a/pkg/front_end/lib/src/kernel/body_builder_context.dart b/pkg/front_end/lib/src/kernel/body_builder_context.dart index 3d0e172b256..7fd4d79df85 100644 --- a/pkg/front_end/lib/src/kernel/body_builder_context.dart +++ b/pkg/front_end/lib/src/kernel/body_builder_context.dart @@ -327,6 +327,14 @@ abstract class BodyBuilderContext { ); } + /// Returns `true` if the member being built is a non-late instance field + /// in a declaration with a primary constructor. + /// + /// Field initializers in this context have access to primary constructor + /// parameters and should be built as if they occur in a constructor + /// initializer. + bool get inPrimaryConstructorFieldInitializer => false; + /// Returns the primary constructor parameters available in the initializer /// scope for instance field initializers. /// diff --git a/pkg/front_end/lib/src/kernel/kernel_target.dart b/pkg/front_end/lib/src/kernel/kernel_target.dart index ecea0aabe67..a32b50cd8c5 100644 --- a/pkg/front_end/lib/src/kernel/kernel_target.dart +++ b/pkg/front_end/lib/src/kernel/kernel_target.dart @@ -1669,7 +1669,7 @@ class KernelTarget { ], ); } - } else { + } else if (!constructor.isConst) { constructor.prependInitializer( field.takePrimaryConstructorFieldInitializer(), ); diff --git a/pkg/front_end/lib/src/kernel/resolver.dart b/pkg/front_end/lib/src/kernel/resolver.dart index c16c0cc5254..123a08a0955 100644 --- a/pkg/front_end/lib/src/kernel/resolver.dart +++ b/pkg/front_end/lib/src/kernel/resolver.dart @@ -262,6 +262,8 @@ class Resolver { fileUri: fileUri, ); ConstantContext constantContext = bodyBuilderContext.constantContext; + List? primaryConstructorInitializerScopeParameters = + bodyBuilderContext.primaryConstructorInitializerScopeParameters; BodyBuilder bodyBuilder = _createBodyBuilder( context: context, bodyBuilderContext: bodyBuilderContext, @@ -277,6 +279,12 @@ class Resolver { startToken: startToken, isLate: isLate, ); + _declareFormals( + typeInferrer: context.typeInferrer, + bodyBuilderContext: bodyBuilderContext, + thisVariable: null, + formals: primaryConstructorInitializerScopeParameters, + ); ExpressionInferenceResult expressionInferenceResult = context.typeInferrer .inferFieldInitializer( fileUri: fileUri, diff --git a/pkg/front_end/lib/src/source/builder_factory.dart b/pkg/front_end/lib/src/source/builder_factory.dart index cab914b05ad..118d9ef1dc0 100644 --- a/pkg/front_end/lib/src/source/builder_factory.dart +++ b/pkg/front_end/lib/src/source/builder_factory.dart @@ -671,7 +671,6 @@ class BuilderFactory { name: fragment.name, typeParameters: typeParameters, underscoreEnumTypeBuilder: _loader.target.underscoreEnumType, - interfaceBuilders: fragment.interfaces, enumElements: fragment.enumElements, libraryBuilder: _enclosingLibraryBuilder, fileUri: fragment.fileUri, @@ -685,6 +684,7 @@ class BuilderFactory { fragment, _loader.target.underscoreEnumType, ), + modifiers: fragment.modifiers, ); fragment.builder = enumBuilder; fragment.bodyScope.declarationBuilder = enumBuilder; diff --git a/pkg/front_end/lib/src/source/fragment_factory_impl.dart b/pkg/front_end/lib/src/source/fragment_factory_impl.dart index 11a212c9d4a..6d16dfa2923 100644 --- a/pkg/front_end/lib/src/source/fragment_factory_impl.dart +++ b/pkg/front_end/lib/src/source/fragment_factory_impl.dart @@ -1089,9 +1089,15 @@ class FragmentFactoryImpl implements FragmentFactory { }) { EnumFragment declarationFragment = endEnumDeclaration(); + Modifiers modifiers = Modifiers.empty; + if (declarationFragment.declaresConstConstructor) { + modifiers |= Modifiers.DeclaresConstConstructor; + } + declarationFragment.compilationUnitScope = _compilationUnitScope; declarationFragment.metadata = metadata; declarationFragment.mixins = mixins; + declarationFragment.modifiers = modifiers; declarationFragment.interfaces = interfaces; declarationFragment.startOffset = startOffset; declarationFragment.endOffset = endOffset; @@ -2137,13 +2143,7 @@ class FragmentFactoryImpl implements FragmentFactory { List fieldInfos, ) { for (FieldInfo info in fieldInfos) { - bool isConst = modifiers.isConst; - bool isFinal = modifiers.isFinal; - bool potentiallyNeedInitializerInOutline = isConst || isFinal; - Token? startToken; - if (potentiallyNeedInitializerInOutline || type == null) { - startToken = info.initializerToken; - } + Token? startToken = info.initializerToken; if (startToken != null) { // Extract only the tokens for the initializer expression from the // token stream. @@ -2151,7 +2151,6 @@ class FragmentFactoryImpl implements FragmentFactory { endToken.setNext(new Token.eof(endToken.next!.offset)); new Token.eof(startToken.previous!.offset).setNext(startToken); } - bool hasInitializer = info.initializerToken != null; offsetMap.registerField( info.identifier, _addField( @@ -2163,10 +2162,6 @@ class FragmentFactoryImpl implements FragmentFactory { nameOffset: info.identifier.nameOffset, endOffset: info.endOffset, initializerToken: startToken, - hasInitializer: hasInitializer, - constInitializerToken: potentiallyNeedInitializerInOutline - ? startToken - : null, ), ); } @@ -2181,12 +2176,10 @@ class FragmentFactoryImpl implements FragmentFactory { required int nameOffset, required int endOffset, required Token? initializerToken, - required bool hasInitializer, - Token? constInitializerToken, }) { DeclarationFragmentImpl? enclosingDeclaration = _declarationFragments.currentOrNull; - if (hasInitializer) { + if (initializerToken != null) { modifiers |= Modifiers.HasInitializer; } FieldFragment fragment = new FieldFragment( @@ -2195,7 +2188,6 @@ class FragmentFactoryImpl implements FragmentFactory { nameOffset: nameOffset, endOffset: endOffset, initializerToken: initializerToken, - constInitializerToken: constInitializerToken, metadata: metadata, type: type, isTopLevel: isTopLevel, diff --git a/pkg/front_end/lib/src/source/source_class_builder.dart b/pkg/front_end/lib/src/source/source_class_builder.dart index 9f5da395357..a52b2b33d42 100644 --- a/pkg/front_end/lib/src/source/source_class_builder.dart +++ b/pkg/front_end/lib/src/source/source_class_builder.dart @@ -167,7 +167,11 @@ class SourceClassBuilder extends ClassBuilderImpl indexedClass, isAugmentation: modifiers.isAugment, ) { - cls.hasConstConstructor = declaresConstConstructor; + if (!isEnum) { + // TODO(johnniwinther): Should enums be marked as having constant + // constructors? + cls.hasConstConstructor = declaresConstConstructor; + } } @override @@ -194,6 +198,17 @@ class SourceClassBuilder extends ClassBuilderImpl includeDuplicates: includeDuplicates, ); + /// Returns `true` if this class has a primary constructor. + bool get hasPrimaryConstructor { + for (SourceMemberBuilder constructorBuilder in _constructorBuilders) { + if (constructorBuilder is SourceConstructorBuilder && + constructorBuilder.isPrimaryConstructor) { + return true; + } + } + return false; + } + /// If the class has a primary constructor, returns the parameters /// available in the initializer scope. Otherwise return `null`. List? @@ -638,6 +653,14 @@ class SourceClassBuilder extends ClassBuilderImpl filteredMembersIterator( includeDuplicates: false, ).forEach(build); + + for (SourceMemberBuilder memberBuilder in _constructorBuilders) { + if (memberBuilder is SourceConstructorBuilder && + memberBuilder.isPrimaryConstructor && + memberBuilder.isConst) { + memberBuilder.buildPrimaryConstructorFieldInitializers(); + } + } } /// Looks up the constructor by [name] on the class built by this class diff --git a/pkg/front_end/lib/src/source/source_constructor_builder.dart b/pkg/front_end/lib/src/source/source_constructor_builder.dart index 09c32fa2743..cef23963527 100644 --- a/pkg/front_end/lib/src/source/source_constructor_builder.dart +++ b/pkg/front_end/lib/src/source/source_constructor_builder.dart @@ -21,6 +21,7 @@ import '../builder/function_signature.dart'; import '../builder/member_builder.dart'; import '../builder/metadata_builder.dart'; import '../builder/omitted_type_builder.dart'; +import '../builder/property_builder.dart'; import '../fragment/constructor/declaration.dart'; import '../kernel/hierarchy/class_member.dart' show ClassMember; import '../kernel/kernel_helper.dart' show DelayedDefaultValueCloner; @@ -145,6 +146,32 @@ class SourceConstructorBuilder extends SourceMemberBuilderImpl return null; } + void buildPrimaryConstructorFieldInitializers() { + List nonLateClassInstanceFieldsWithInitializers = []; + + Iterator fieldIterator = declarationBuilder + .filteredMembersIterator(includeDuplicates: false); + while (fieldIterator.moveNext()) { + SourcePropertyBuilder fieldBuilder = fieldIterator.current; + if (fieldBuilder.hasConcreteField && + declarationBuilder is SourceClassBuilder && + fieldBuilder.isDeclarationInstanceMember && + !fieldBuilder.isLate && + fieldBuilder.hasInitializer) { + nonLateClassInstanceFieldsWithInitializers.add(fieldBuilder); + } + } + // We prepend the initializers in reversed order to preserve normal + // field initializer evaluation order. + for (SourcePropertyBuilder field + in nonLateClassInstanceFieldsWithInitializers.reversed) { + FieldInitialization? fieldInitialization = _initializedFields?[field]; + if (fieldInitialization == null) { + prependInitializer(field.takePrimaryConstructorFieldInitializer()); + } + } + } + // TODO(johnniwinther): Add annotations to tear-offs. Iterable get annotatables => [invokeTarget]; diff --git a/pkg/front_end/lib/src/source/source_enum_builder.dart b/pkg/front_end/lib/src/source/source_enum_builder.dart index 3d6faac23a9..bc71a2c4237 100644 --- a/pkg/front_end/lib/src/source/source_enum_builder.dart +++ b/pkg/front_end/lib/src/source/source_enum_builder.dart @@ -78,7 +78,7 @@ class SourceEnumBuilder extends SourceClassBuilder { late final _EnumValuesFieldDeclaration _enumValuesFieldDeclaration; - SourceEnumBuilder.internal({ + SourceEnumBuilder({ required String name, required List? typeParameters, required TypeBuilder underscoreEnumTypeBuilder, @@ -92,11 +92,12 @@ class SourceEnumBuilder extends SourceClassBuilder { required this.endOffset, required IndexedClass? indexedClass, required ClassDeclaration classDeclaration, + required Modifiers modifiers, }) : _underscoreEnumTypeBuilder = underscoreEnumTypeBuilder, _introductory = classDeclaration, _enumElements = enumElements, super( - modifiers: Modifiers.empty, + modifiers: modifiers, name: name, typeParameters: typeParameters, typeParameterScope: typeParameterScope, @@ -108,40 +109,6 @@ class SourceEnumBuilder extends SourceClassBuilder { introductory: classDeclaration, ); - factory SourceEnumBuilder({ - required String name, - required List? typeParameters, - required TypeBuilder underscoreEnumTypeBuilder, - required List? interfaceBuilders, - required List enumElements, - required SourceLibraryBuilder libraryBuilder, - required Uri fileUri, - required int startOffset, - required int nameOffset, - required int endOffset, - required IndexedClass? indexedClass, - required LookupScope typeParameterScope, - required DeclarationNameSpaceBuilder nameSpaceBuilder, - required ClassDeclaration classDeclaration, - }) { - SourceEnumBuilder enumBuilder = new SourceEnumBuilder.internal( - name: name, - typeParameters: typeParameters, - underscoreEnumTypeBuilder: underscoreEnumTypeBuilder, - typeParameterScope: typeParameterScope, - nameSpaceBuilder: nameSpaceBuilder, - enumElements: enumElements, - libraryBuilder: libraryBuilder, - fileUri: fileUri, - startOffset: startOffset, - nameOffset: nameOffset, - endOffset: endOffset, - indexedClass: indexedClass, - classDeclaration: classDeclaration, - ); - return enumBuilder; - } - @override void buildScopes(LibraryBuilder coreLibrary) { _createTypeBuilders(coreLibrary); @@ -732,7 +699,7 @@ class _EnumValuesFieldDeclaration required DeclarationBuilder? declarationBuilder, required List annotatables, required Uri annotatablesFileUri, - required bool isClassInstanceMember, + required bool forConstantConstructor, }) { List values = []; for (EnumElementFragment enumElement in _sourceEnumBuilder._enumElements) { diff --git a/pkg/front_end/lib/src/source/source_property_builder.dart b/pkg/front_end/lib/src/source/source_property_builder.dart index 35eb709e2aa..ab954dad0d9 100644 --- a/pkg/front_end/lib/src/source/source_property_builder.dart +++ b/pkg/front_end/lib/src/source/source_property_builder.dart @@ -192,6 +192,7 @@ class SourcePropertyBuilder extends SourceMemberBuilderImpl ClassHierarchy classHierarchy, List delayedDefaultValueCloners, ) { + DeclarationBuilder? declarationBuilder = this.declarationBuilder; if (!hasBuiltOutlineExpressions) { _introductoryField?.buildFieldOutlineExpressions( classHierarchy: classHierarchy, @@ -203,7 +204,10 @@ class SourcePropertyBuilder extends SourceMemberBuilderImpl writeTarget as Annotatable, ], annotatablesFileUri: readTarget!.fileUri, - isClassInstanceMember: isClassInstanceMember, + forConstantConstructor: + declarationBuilder is SourceClassBuilder && + !isStatic && + declarationBuilder.declaresConstConstructor, ); _introductoryGetable?.buildGetterOutlineExpressions( classHierarchy: classHierarchy, diff --git a/pkg/front_end/testcases/enhanced_enums/members.dart.strong.outline.expect b/pkg/front_end/testcases/enhanced_enums/members.dart.strong.outline.expect index d2fc9ea3220..784fbeb4662 100644 --- a/pkg/front_end/testcases/enhanced_enums/members.dart.strong.outline.expect +++ b/pkg/front_end/testcases/enhanced_enums/members.dart.strong.outline.expect @@ -6,7 +6,7 @@ class E extends core::_Enum /*isEnum*/ { enum-element static const field self::E one = const self::E::•(0, "one", 1); enum-element static const field self::E two = const self::E::•(1, "two", 2); final field core::int foo; - final field core::int bar; + final field core::int bar = 42; static field self::E staticFoo; static const field core::List values = const [self::E::one, self::E::two]; const constructor •(core::int #index, core::String #name, core::int foo) → self::E @@ -25,7 +25,7 @@ class E2 extends core::_Enum /*isEnum*/ { enum-element static const field self::E2 one = const self::E2::•(0, "one", 1); enum-element static const field self::E2 two = const self::E2::•(1, "two", "2"); final field self::E2::X% foo; - final field self::E2::X? bar; + final field self::E2::X? bar = null; static field () → self::E2 staticFoo; static const field core::List> values = const >[self::E2::one, self::E2::two]; const constructor •(core::int #index, core::String #name, self::E2::X% foo) → self::E2 @@ -45,9 +45,9 @@ static method main() → dynamic Extra constant evaluation status: -Evaluated: ConstructorInvocation @ org-dartlang-testcase:///members.dart:6:3 -> InstanceConstant(const E{E.foo: 1, E.bar: null, _Enum.index: 0, _Enum._name: "one"}) -Evaluated: ConstructorInvocation @ org-dartlang-testcase:///members.dart:7:3 -> InstanceConstant(const E{E.foo: 2, E.bar: null, _Enum.index: 1, _Enum._name: "two"}) -Evaluated: ListLiteral @ org-dartlang-testcase:///members.dart:5:6 -> ListConstant(const [const E{E.foo: 1, E.bar: null, _Enum.index: 0, _Enum._name: "one"}, const E{E.foo: 2, E.bar: null, _Enum.index: 1, _Enum._name: "two"}]) +Evaluated: ConstructorInvocation @ org-dartlang-testcase:///members.dart:6:3 -> InstanceConstant(const E{E.foo: 1, E.bar: 42, _Enum.index: 0, _Enum._name: "one"}) +Evaluated: ConstructorInvocation @ org-dartlang-testcase:///members.dart:7:3 -> InstanceConstant(const E{E.foo: 2, E.bar: 42, _Enum.index: 1, _Enum._name: "two"}) +Evaluated: ListLiteral @ org-dartlang-testcase:///members.dart:5:6 -> ListConstant(const [const E{E.foo: 1, E.bar: 42, _Enum.index: 0, _Enum._name: "one"}, const E{E.foo: 2, E.bar: 42, _Enum.index: 1, _Enum._name: "two"}]) Evaluated: ConstructorInvocation @ org-dartlang-testcase:///members.dart:24:3 -> InstanceConstant(const E2{E2.foo: 1, E2.bar: null, _Enum.index: 0, _Enum._name: "one"}) Evaluated: ConstructorInvocation @ org-dartlang-testcase:///members.dart:25:3 -> InstanceConstant(const E2{E2.foo: "2", E2.bar: null, _Enum.index: 1, _Enum._name: "two"}) Evaluated: ListLiteral @ org-dartlang-testcase:///members.dart:23:6 -> ListConstant(const >[const E2{E2.foo: 1, E2.bar: null, _Enum.index: 0, _Enum._name: "one"}, const E2{E2.foo: "2", E2.bar: null, _Enum.index: 1, _Enum._name: "two"}]) diff --git a/pkg/front_end/testcases/general/constants/issue_43431.dart.strong.outline.expect b/pkg/front_end/testcases/general/constants/issue_43431.dart.strong.outline.expect index f47c76dcbd8..60dcee54efd 100644 --- a/pkg/front_end/testcases/general/constants/issue_43431.dart.strong.outline.expect +++ b/pkg/front_end/testcases/general/constants/issue_43431.dart.strong.outline.expect @@ -16,7 +16,7 @@ import self as self; import "dart:core" as core; class Foo extends core::Object /*hasConstConstructor*/ { - field self::Foo x; + field self::Foo x = const self::Foo::•(); const constructor •({core::bool x = true}) → self::Foo : super core::Object::•() ; diff --git a/pkg/front_end/testcases/primary_constructors/const_parameters.dart b/pkg/front_end/testcases/primary_constructors/const_parameters.dart new file mode 100644 index 00000000000..290bbcae7d7 --- /dev/null +++ b/pkg/front_end/testcases/primary_constructors/const_parameters.dart @@ -0,0 +1,75 @@ +// Copyright (c) 2026, 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. + +class C0 { + final int a; + final int b; + const new(int c, dynamic d) : a = d.length, b = c; +} + +class const C1(int c, dynamic d) { + final int a = d.length; + final int b = c; +} + +class const C2(int c, dynamic d) { + final int a; + final int b; + + this : a = d.length, b = c; +} + +class const C3(int c, dynamic d) { + final int a = d.length; + final int b; + + this : b = c; +} + +class const C4(int c, dynamic d) { + final int a = d.length; + final int b = c; + + this : a = d.length, b = c; +} + +class const C5(int c, dynamic d) { + int a = d.length; + int b = c; + int? _; +} + +class const C6(int c, dynamic d) { + var a = d.length; + var b = c; + var _; +} + +main() { + const a = C0(0, '1234'); + expect(4, a.a); + expect(0, a.b); + + const b = C1(1, '12345'); + expect(5, b.a); + expect(1, b.b); + + const c = C2(2, '123456'); + expect(6, c.a); + expect(2, c.b); + + const d = C3(3, '1234567'); + expect(7, d.a); + expect(3, d.b); +} + +test() { + const e = C4(0, ''); + const f = C5(0, ''); + const g = C6(0, ''); +} + +expect(expected, actual) { + if (expected != actual) throw 'Expected $expected, actual $actual'; +} diff --git a/pkg/front_end/testcases/primary_constructors/const_parameters.dart.strong.expect b/pkg/front_end/testcases/primary_constructors/const_parameters.dart.strong.expect new file mode 100644 index 00000000000..fba58a9b2f4 --- /dev/null +++ b/pkg/front_end/testcases/primary_constructors/const_parameters.dart.strong.expect @@ -0,0 +1,157 @@ +library; +// +// Problems in library: +// +// pkg/front_end/testcases/primary_constructors/const_parameters.dart:34:10: Error: 'a' is a final instance variable that was initialized at the declaration. +// this : a = d.length, b = c; +// ^ +// pkg/front_end/testcases/primary_constructors/const_parameters.dart:31:13: Context: 'a' was initialized here. +// final int a = d.length; +// ^ +// +// pkg/front_end/testcases/primary_constructors/const_parameters.dart:34:24: Error: 'b' is a final instance variable that was initialized at the declaration. +// this : a = d.length, b = c; +// ^ +// pkg/front_end/testcases/primary_constructors/const_parameters.dart:32:13: Context: 'b' was initialized here. +// final int b = c; +// ^ +// +// pkg/front_end/testcases/primary_constructors/const_parameters.dart:37:15: Error: Constructor is marked 'const' so all fields must be final. +// class const C5(int c, dynamic d) { +// ^ +// pkg/front_end/testcases/primary_constructors/const_parameters.dart:38:7: Context: Field isn't final, but constructor is 'const'. +// int a = d.length; +// ^ +// pkg/front_end/testcases/primary_constructors/const_parameters.dart:39:7: Context: Field isn't final, but constructor is 'const'. +// int b = c; +// ^ +// pkg/front_end/testcases/primary_constructors/const_parameters.dart:40:8: Context: Field isn't final, but constructor is 'const'. +// int? _; +// ^ +// +// pkg/front_end/testcases/primary_constructors/const_parameters.dart:43:15: Error: Constructor is marked 'const' so all fields must be final. +// class const C6(int c, dynamic d) { +// ^ +// pkg/front_end/testcases/primary_constructors/const_parameters.dart:44:7: Context: Field isn't final, but constructor is 'const'. +// var a = d.length; +// ^ +// pkg/front_end/testcases/primary_constructors/const_parameters.dart:45:7: Context: Field isn't final, but constructor is 'const'. +// var b = c; +// ^ +// pkg/front_end/testcases/primary_constructors/const_parameters.dart:46:7: Context: Field isn't final, but constructor is 'const'. +// var _; +// ^ +// +import self as self; +import "dart:core" as core; + +class C0 extends core::Object /*hasConstConstructor*/ { + final field core::int a; + final field core::int b; + const constructor •(core::int c, dynamic d) → self::C0 + : self::C0::a = d{dynamic}.length as{TypeError,ForDynamic} core::int, self::C0::b = c, super core::Object::•() + ; +} +class C1 extends core::Object /*hasConstConstructor*/ { + final field core::int a; + final field core::int b; + const constructor •(final core::int c, final dynamic d) → self::C1 + : self::C1::a = d{dynamic}.length as{TypeError,ForDynamic} core::int, self::C1::b = c, super core::Object::•() + ; +} +class C2 extends core::Object /*hasConstConstructor*/ { + final field core::int a; + final field core::int b; + const constructor •(final core::int c, final dynamic d) → self::C2 + : self::C2::a = d{dynamic}.length as{TypeError,ForDynamic} core::int, self::C2::b = c, super core::Object::•() + ; +} +class C3 extends core::Object /*hasConstConstructor*/ { + final field core::int a; + final field core::int b; + const constructor •(final core::int c, final dynamic d) → self::C3 + : self::C3::a = d{dynamic}.length as{TypeError,ForDynamic} core::int, self::C3::b = c, super core::Object::•() + ; +} +class C4 extends core::Object /*hasConstConstructor*/ { + final field core::int a; + final field core::int b; + const constructor •(final core::int c, final dynamic d) → self::C4 + : self::C4::a = d{dynamic}.length as{TypeError,ForDynamic} core::int, self::C4::b = c, invalid-initializer "pkg/front_end/testcases/primary_constructors/const_parameters.dart:34:10: Error: 'a' is a final instance variable that was initialized at the declaration. + this : a = d.length, b = c; + ^", invalid-initializer "pkg/front_end/testcases/primary_constructors/const_parameters.dart:34:24: Error: 'b' is a final instance variable that was initialized at the declaration. + this : a = d.length, b = c; + ^" + ; +} +class C5 extends core::Object /*hasConstConstructor*/ { + field core::int a; + field core::int b; + field core::int? _ = null; + const constructor •(final core::int c, final dynamic d) → self::C5 + : self::C5::a = d{dynamic}.length as{TypeError,ForDynamic} core::int, self::C5::b = c, super core::Object::•() + ; +} +class C6 extends core::Object /*hasConstConstructor*/ { + field dynamic a; + field core::int b; + field dynamic _ = null; + const constructor •(final core::int c, final dynamic d) → self::C6 + : self::C6::a = d{dynamic}.length, self::C6::b = c, super core::Object::•() + ; +} +static method main() → dynamic { + const self::C0 a = #C3; + self::expect(4, #C3.{self::C0::a}{core::int}); + self::expect(0, #C3.{self::C0::b}{core::int}); + const self::C1 b = #C6; + self::expect(5, #C6.{self::C1::a}{core::int}); + self::expect(1, #C6.{self::C1::b}{core::int}); + const self::C2 c = #C9; + self::expect(6, #C9.{self::C2::a}{core::int}); + self::expect(2, #C9.{self::C2::b}{core::int}); + const self::C3 d = #C12; + self::expect(7, #C12.{self::C3::a}{core::int}); + self::expect(3, #C12.{self::C3::b}{core::int}); +} +static method test() → dynamic { + const self::C4 e = invalid-expression "pkg/front_end/testcases/primary_constructors/const_parameters.dart:34:10: Error: 'a' is a final instance variable that was initialized at the declaration. + this : a = d.length, b = c; + ^"; + const self::C5 f = #C14; + const self::C6 g = #C15; +} +static method expect(dynamic expected, dynamic actual) → dynamic { + if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual)) + throw "Expected ${expected}, actual ${actual}"; +} + +constants { + #C1 = 4 + #C2 = 0 + #C3 = self::C0 {a:#C1, b:#C2} + #C4 = 5 + #C5 = 1 + #C6 = self::C1 {a:#C4, b:#C5} + #C7 = 6 + #C8 = 2 + #C9 = self::C2 {a:#C7, b:#C8} + #C10 = 7 + #C11 = 3 + #C12 = self::C3 {a:#C10, b:#C11} + #C13 = null + #C14 = self::C5 {a:#C2, b:#C2, _:#C13} + #C15 = self::C6 {a:#C2, b:#C2, _:#C13} +} + + +Constructor coverage from constants: +org-dartlang-testcase:///const_parameters.dart: +- C0. (from org-dartlang-testcase:///const_parameters.dart:8:9) +- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart) +- C1. (from org-dartlang-testcase:///const_parameters.dart:11:15) +- C2. (from org-dartlang-testcase:///const_parameters.dart:16:15) +- C3. (from org-dartlang-testcase:///const_parameters.dart:23:15) +- C4. (from org-dartlang-testcase:///const_parameters.dart:30:15) +- C5. (from org-dartlang-testcase:///const_parameters.dart:37:15) +- C6. (from org-dartlang-testcase:///const_parameters.dart:43:15) diff --git a/pkg/front_end/testcases/primary_constructors/const_parameters.dart.strong.modular.expect b/pkg/front_end/testcases/primary_constructors/const_parameters.dart.strong.modular.expect new file mode 100644 index 00000000000..fba58a9b2f4 --- /dev/null +++ b/pkg/front_end/testcases/primary_constructors/const_parameters.dart.strong.modular.expect @@ -0,0 +1,157 @@ +library; +// +// Problems in library: +// +// pkg/front_end/testcases/primary_constructors/const_parameters.dart:34:10: Error: 'a' is a final instance variable that was initialized at the declaration. +// this : a = d.length, b = c; +// ^ +// pkg/front_end/testcases/primary_constructors/const_parameters.dart:31:13: Context: 'a' was initialized here. +// final int a = d.length; +// ^ +// +// pkg/front_end/testcases/primary_constructors/const_parameters.dart:34:24: Error: 'b' is a final instance variable that was initialized at the declaration. +// this : a = d.length, b = c; +// ^ +// pkg/front_end/testcases/primary_constructors/const_parameters.dart:32:13: Context: 'b' was initialized here. +// final int b = c; +// ^ +// +// pkg/front_end/testcases/primary_constructors/const_parameters.dart:37:15: Error: Constructor is marked 'const' so all fields must be final. +// class const C5(int c, dynamic d) { +// ^ +// pkg/front_end/testcases/primary_constructors/const_parameters.dart:38:7: Context: Field isn't final, but constructor is 'const'. +// int a = d.length; +// ^ +// pkg/front_end/testcases/primary_constructors/const_parameters.dart:39:7: Context: Field isn't final, but constructor is 'const'. +// int b = c; +// ^ +// pkg/front_end/testcases/primary_constructors/const_parameters.dart:40:8: Context: Field isn't final, but constructor is 'const'. +// int? _; +// ^ +// +// pkg/front_end/testcases/primary_constructors/const_parameters.dart:43:15: Error: Constructor is marked 'const' so all fields must be final. +// class const C6(int c, dynamic d) { +// ^ +// pkg/front_end/testcases/primary_constructors/const_parameters.dart:44:7: Context: Field isn't final, but constructor is 'const'. +// var a = d.length; +// ^ +// pkg/front_end/testcases/primary_constructors/const_parameters.dart:45:7: Context: Field isn't final, but constructor is 'const'. +// var b = c; +// ^ +// pkg/front_end/testcases/primary_constructors/const_parameters.dart:46:7: Context: Field isn't final, but constructor is 'const'. +// var _; +// ^ +// +import self as self; +import "dart:core" as core; + +class C0 extends core::Object /*hasConstConstructor*/ { + final field core::int a; + final field core::int b; + const constructor •(core::int c, dynamic d) → self::C0 + : self::C0::a = d{dynamic}.length as{TypeError,ForDynamic} core::int, self::C0::b = c, super core::Object::•() + ; +} +class C1 extends core::Object /*hasConstConstructor*/ { + final field core::int a; + final field core::int b; + const constructor •(final core::int c, final dynamic d) → self::C1 + : self::C1::a = d{dynamic}.length as{TypeError,ForDynamic} core::int, self::C1::b = c, super core::Object::•() + ; +} +class C2 extends core::Object /*hasConstConstructor*/ { + final field core::int a; + final field core::int b; + const constructor •(final core::int c, final dynamic d) → self::C2 + : self::C2::a = d{dynamic}.length as{TypeError,ForDynamic} core::int, self::C2::b = c, super core::Object::•() + ; +} +class C3 extends core::Object /*hasConstConstructor*/ { + final field core::int a; + final field core::int b; + const constructor •(final core::int c, final dynamic d) → self::C3 + : self::C3::a = d{dynamic}.length as{TypeError,ForDynamic} core::int, self::C3::b = c, super core::Object::•() + ; +} +class C4 extends core::Object /*hasConstConstructor*/ { + final field core::int a; + final field core::int b; + const constructor •(final core::int c, final dynamic d) → self::C4 + : self::C4::a = d{dynamic}.length as{TypeError,ForDynamic} core::int, self::C4::b = c, invalid-initializer "pkg/front_end/testcases/primary_constructors/const_parameters.dart:34:10: Error: 'a' is a final instance variable that was initialized at the declaration. + this : a = d.length, b = c; + ^", invalid-initializer "pkg/front_end/testcases/primary_constructors/const_parameters.dart:34:24: Error: 'b' is a final instance variable that was initialized at the declaration. + this : a = d.length, b = c; + ^" + ; +} +class C5 extends core::Object /*hasConstConstructor*/ { + field core::int a; + field core::int b; + field core::int? _ = null; + const constructor •(final core::int c, final dynamic d) → self::C5 + : self::C5::a = d{dynamic}.length as{TypeError,ForDynamic} core::int, self::C5::b = c, super core::Object::•() + ; +} +class C6 extends core::Object /*hasConstConstructor*/ { + field dynamic a; + field core::int b; + field dynamic _ = null; + const constructor •(final core::int c, final dynamic d) → self::C6 + : self::C6::a = d{dynamic}.length, self::C6::b = c, super core::Object::•() + ; +} +static method main() → dynamic { + const self::C0 a = #C3; + self::expect(4, #C3.{self::C0::a}{core::int}); + self::expect(0, #C3.{self::C0::b}{core::int}); + const self::C1 b = #C6; + self::expect(5, #C6.{self::C1::a}{core::int}); + self::expect(1, #C6.{self::C1::b}{core::int}); + const self::C2 c = #C9; + self::expect(6, #C9.{self::C2::a}{core::int}); + self::expect(2, #C9.{self::C2::b}{core::int}); + const self::C3 d = #C12; + self::expect(7, #C12.{self::C3::a}{core::int}); + self::expect(3, #C12.{self::C3::b}{core::int}); +} +static method test() → dynamic { + const self::C4 e = invalid-expression "pkg/front_end/testcases/primary_constructors/const_parameters.dart:34:10: Error: 'a' is a final instance variable that was initialized at the declaration. + this : a = d.length, b = c; + ^"; + const self::C5 f = #C14; + const self::C6 g = #C15; +} +static method expect(dynamic expected, dynamic actual) → dynamic { + if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual)) + throw "Expected ${expected}, actual ${actual}"; +} + +constants { + #C1 = 4 + #C2 = 0 + #C3 = self::C0 {a:#C1, b:#C2} + #C4 = 5 + #C5 = 1 + #C6 = self::C1 {a:#C4, b:#C5} + #C7 = 6 + #C8 = 2 + #C9 = self::C2 {a:#C7, b:#C8} + #C10 = 7 + #C11 = 3 + #C12 = self::C3 {a:#C10, b:#C11} + #C13 = null + #C14 = self::C5 {a:#C2, b:#C2, _:#C13} + #C15 = self::C6 {a:#C2, b:#C2, _:#C13} +} + + +Constructor coverage from constants: +org-dartlang-testcase:///const_parameters.dart: +- C0. (from org-dartlang-testcase:///const_parameters.dart:8:9) +- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart) +- C1. (from org-dartlang-testcase:///const_parameters.dart:11:15) +- C2. (from org-dartlang-testcase:///const_parameters.dart:16:15) +- C3. (from org-dartlang-testcase:///const_parameters.dart:23:15) +- C4. (from org-dartlang-testcase:///const_parameters.dart:30:15) +- C5. (from org-dartlang-testcase:///const_parameters.dart:37:15) +- C6. (from org-dartlang-testcase:///const_parameters.dart:43:15) diff --git a/pkg/front_end/testcases/primary_constructors/const_parameters.dart.strong.outline.expect b/pkg/front_end/testcases/primary_constructors/const_parameters.dart.strong.outline.expect new file mode 100644 index 00000000000..796570a4659 --- /dev/null +++ b/pkg/front_end/testcases/primary_constructors/const_parameters.dart.strong.outline.expect @@ -0,0 +1,61 @@ +library; +import self as self; +import "dart:core" as core; + +class C0 extends core::Object /*hasConstConstructor*/ { + final field core::int a; + final field core::int b; + const constructor •(core::int c, dynamic d) → self::C0 + : self::C0::a = d{dynamic}.length as{TypeError,ForDynamic} core::int, self::C0::b = c, super core::Object::•() + ; +} +class C1 extends core::Object /*hasConstConstructor*/ { + final field core::int a; + final field core::int b; + const constructor •(final core::int c, final dynamic d) → self::C1 + : self::C1::a = d{dynamic}.length as{TypeError,ForDynamic} core::int, self::C1::b = c, super core::Object::•() + ; +} +class C2 extends core::Object /*hasConstConstructor*/ { + final field core::int a; + final field core::int b; + const constructor •(final core::int c, final dynamic d) → self::C2 + : super core::Object::•() + ; +} +class C3 extends core::Object /*hasConstConstructor*/ { + final field core::int a; + final field core::int b; + const constructor •(final core::int c, final dynamic d) → self::C3 + : self::C3::a = d{dynamic}.length as{TypeError,ForDynamic} core::int, super core::Object::•() + ; +} +class C4 extends core::Object /*hasConstConstructor*/ { + final field core::int a; + final field core::int b; + const constructor •(final core::int c, final dynamic d) → self::C4 + : self::C4::a = d{dynamic}.length as{TypeError,ForDynamic} core::int, self::C4::b = c, super core::Object::•() + ; +} +class C5 extends core::Object /*hasConstConstructor*/ { + field core::int a; + field core::int b; + field core::int? _; + const constructor •(final core::int c, final dynamic d) → self::C5 + : self::C5::a = d{dynamic}.length as{TypeError,ForDynamic} core::int, self::C5::b = c, super core::Object::•() + ; +} +class C6 extends core::Object /*hasConstConstructor*/ { + field dynamic a; + field core::int b; + field dynamic _; + const constructor •(final core::int c, final dynamic d) → self::C6 + : self::C6::a = d{dynamic}.length, self::C6::b = c, super core::Object::•() + ; +} +static method main() → dynamic + ; +static method test() → dynamic + ; +static method expect(dynamic expected, dynamic actual) → dynamic + ; diff --git a/pkg/front_end/testcases/primary_constructors/const_parameters.dart.strong.transformed.expect b/pkg/front_end/testcases/primary_constructors/const_parameters.dart.strong.transformed.expect new file mode 100644 index 00000000000..fba58a9b2f4 --- /dev/null +++ b/pkg/front_end/testcases/primary_constructors/const_parameters.dart.strong.transformed.expect @@ -0,0 +1,157 @@ +library; +// +// Problems in library: +// +// pkg/front_end/testcases/primary_constructors/const_parameters.dart:34:10: Error: 'a' is a final instance variable that was initialized at the declaration. +// this : a = d.length, b = c; +// ^ +// pkg/front_end/testcases/primary_constructors/const_parameters.dart:31:13: Context: 'a' was initialized here. +// final int a = d.length; +// ^ +// +// pkg/front_end/testcases/primary_constructors/const_parameters.dart:34:24: Error: 'b' is a final instance variable that was initialized at the declaration. +// this : a = d.length, b = c; +// ^ +// pkg/front_end/testcases/primary_constructors/const_parameters.dart:32:13: Context: 'b' was initialized here. +// final int b = c; +// ^ +// +// pkg/front_end/testcases/primary_constructors/const_parameters.dart:37:15: Error: Constructor is marked 'const' so all fields must be final. +// class const C5(int c, dynamic d) { +// ^ +// pkg/front_end/testcases/primary_constructors/const_parameters.dart:38:7: Context: Field isn't final, but constructor is 'const'. +// int a = d.length; +// ^ +// pkg/front_end/testcases/primary_constructors/const_parameters.dart:39:7: Context: Field isn't final, but constructor is 'const'. +// int b = c; +// ^ +// pkg/front_end/testcases/primary_constructors/const_parameters.dart:40:8: Context: Field isn't final, but constructor is 'const'. +// int? _; +// ^ +// +// pkg/front_end/testcases/primary_constructors/const_parameters.dart:43:15: Error: Constructor is marked 'const' so all fields must be final. +// class const C6(int c, dynamic d) { +// ^ +// pkg/front_end/testcases/primary_constructors/const_parameters.dart:44:7: Context: Field isn't final, but constructor is 'const'. +// var a = d.length; +// ^ +// pkg/front_end/testcases/primary_constructors/const_parameters.dart:45:7: Context: Field isn't final, but constructor is 'const'. +// var b = c; +// ^ +// pkg/front_end/testcases/primary_constructors/const_parameters.dart:46:7: Context: Field isn't final, but constructor is 'const'. +// var _; +// ^ +// +import self as self; +import "dart:core" as core; + +class C0 extends core::Object /*hasConstConstructor*/ { + final field core::int a; + final field core::int b; + const constructor •(core::int c, dynamic d) → self::C0 + : self::C0::a = d{dynamic}.length as{TypeError,ForDynamic} core::int, self::C0::b = c, super core::Object::•() + ; +} +class C1 extends core::Object /*hasConstConstructor*/ { + final field core::int a; + final field core::int b; + const constructor •(final core::int c, final dynamic d) → self::C1 + : self::C1::a = d{dynamic}.length as{TypeError,ForDynamic} core::int, self::C1::b = c, super core::Object::•() + ; +} +class C2 extends core::Object /*hasConstConstructor*/ { + final field core::int a; + final field core::int b; + const constructor •(final core::int c, final dynamic d) → self::C2 + : self::C2::a = d{dynamic}.length as{TypeError,ForDynamic} core::int, self::C2::b = c, super core::Object::•() + ; +} +class C3 extends core::Object /*hasConstConstructor*/ { + final field core::int a; + final field core::int b; + const constructor •(final core::int c, final dynamic d) → self::C3 + : self::C3::a = d{dynamic}.length as{TypeError,ForDynamic} core::int, self::C3::b = c, super core::Object::•() + ; +} +class C4 extends core::Object /*hasConstConstructor*/ { + final field core::int a; + final field core::int b; + const constructor •(final core::int c, final dynamic d) → self::C4 + : self::C4::a = d{dynamic}.length as{TypeError,ForDynamic} core::int, self::C4::b = c, invalid-initializer "pkg/front_end/testcases/primary_constructors/const_parameters.dart:34:10: Error: 'a' is a final instance variable that was initialized at the declaration. + this : a = d.length, b = c; + ^", invalid-initializer "pkg/front_end/testcases/primary_constructors/const_parameters.dart:34:24: Error: 'b' is a final instance variable that was initialized at the declaration. + this : a = d.length, b = c; + ^" + ; +} +class C5 extends core::Object /*hasConstConstructor*/ { + field core::int a; + field core::int b; + field core::int? _ = null; + const constructor •(final core::int c, final dynamic d) → self::C5 + : self::C5::a = d{dynamic}.length as{TypeError,ForDynamic} core::int, self::C5::b = c, super core::Object::•() + ; +} +class C6 extends core::Object /*hasConstConstructor*/ { + field dynamic a; + field core::int b; + field dynamic _ = null; + const constructor •(final core::int c, final dynamic d) → self::C6 + : self::C6::a = d{dynamic}.length, self::C6::b = c, super core::Object::•() + ; +} +static method main() → dynamic { + const self::C0 a = #C3; + self::expect(4, #C3.{self::C0::a}{core::int}); + self::expect(0, #C3.{self::C0::b}{core::int}); + const self::C1 b = #C6; + self::expect(5, #C6.{self::C1::a}{core::int}); + self::expect(1, #C6.{self::C1::b}{core::int}); + const self::C2 c = #C9; + self::expect(6, #C9.{self::C2::a}{core::int}); + self::expect(2, #C9.{self::C2::b}{core::int}); + const self::C3 d = #C12; + self::expect(7, #C12.{self::C3::a}{core::int}); + self::expect(3, #C12.{self::C3::b}{core::int}); +} +static method test() → dynamic { + const self::C4 e = invalid-expression "pkg/front_end/testcases/primary_constructors/const_parameters.dart:34:10: Error: 'a' is a final instance variable that was initialized at the declaration. + this : a = d.length, b = c; + ^"; + const self::C5 f = #C14; + const self::C6 g = #C15; +} +static method expect(dynamic expected, dynamic actual) → dynamic { + if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual)) + throw "Expected ${expected}, actual ${actual}"; +} + +constants { + #C1 = 4 + #C2 = 0 + #C3 = self::C0 {a:#C1, b:#C2} + #C4 = 5 + #C5 = 1 + #C6 = self::C1 {a:#C4, b:#C5} + #C7 = 6 + #C8 = 2 + #C9 = self::C2 {a:#C7, b:#C8} + #C10 = 7 + #C11 = 3 + #C12 = self::C3 {a:#C10, b:#C11} + #C13 = null + #C14 = self::C5 {a:#C2, b:#C2, _:#C13} + #C15 = self::C6 {a:#C2, b:#C2, _:#C13} +} + + +Constructor coverage from constants: +org-dartlang-testcase:///const_parameters.dart: +- C0. (from org-dartlang-testcase:///const_parameters.dart:8:9) +- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart) +- C1. (from org-dartlang-testcase:///const_parameters.dart:11:15) +- C2. (from org-dartlang-testcase:///const_parameters.dart:16:15) +- C3. (from org-dartlang-testcase:///const_parameters.dart:23:15) +- C4. (from org-dartlang-testcase:///const_parameters.dart:30:15) +- C5. (from org-dartlang-testcase:///const_parameters.dart:37:15) +- C6. (from org-dartlang-testcase:///const_parameters.dart:43:15) diff --git a/pkg/front_end/testcases/primary_constructors/const_parameters.dart.textual_outline.expect b/pkg/front_end/testcases/primary_constructors/const_parameters.dart.textual_outline.expect new file mode 100644 index 00000000000..2de47aecbc3 --- /dev/null +++ b/pkg/front_end/testcases/primary_constructors/const_parameters.dart.textual_outline.expect @@ -0,0 +1,46 @@ +class C0 { + final int a; + final int b; + const new(int c, dynamic d) : a = d.length, b = c; +} + +class const C1(int c, dynamic d) { + final int a = d.length; + final int b = c; +} + +class const C2(int c, dynamic d) { + final int a; + final int b; + this : a = d.length, b = c; +} + +class const C3(int c, dynamic d) { + final int a = d.length; + final int b; + this : b = c; +} + +class const C4(int c, dynamic d) { + final int a = d.length; + final int b = c; + this : a = d.length, b = c; +} + +class const C5(int c, dynamic d) { + int a = d.length; + int b = c; + int? _; +} + +class const C6(int c, dynamic d) { + var a = d.length; + var b = c; + var _; +} + +main() {} + +test() {} + +expect(expected, actual) {} diff --git a/pkg/front_end/testcases/primary_constructors/generic_primary_constructor.dart.strong.outline.expect b/pkg/front_end/testcases/primary_constructors/generic_primary_constructor.dart.strong.outline.expect index 24678d995fa..d98a6f5b612 100644 --- a/pkg/front_end/testcases/primary_constructors/generic_primary_constructor.dart.strong.outline.expect +++ b/pkg/front_end/testcases/primary_constructors/generic_primary_constructor.dart.strong.outline.expect @@ -43,7 +43,7 @@ class E2 extends core::_Enum /*isEnum*/ { final field core::Type f; static const field core::List> values = const >[self::E2::a]; const constructor •(core::int #index, core::String #name, final self::E2::T% a, final self::E2::T% b) → self::E2 - : self::E2::b = b, super core::_Enum::•(#index, #name) + : self::E2::d = a, self::E2::e = b, self::E2::f = self::E2::T%, self::E2::b = b, super core::_Enum::•(#index, #name) ; method core::_enumToString() → core::String return "E2.${this.{core::_Enum::_name}{core::String}}"; @@ -77,6 +77,6 @@ static extension-type-member synthetic method ET2|constructor#_#new#tearOff InstanceConstant(const E1{E1.b: 1, E1.c: 0, E1.d: 1, E1.f: int, _Enum.index: 0, _Enum._name: "a"}) Evaluated: ListLiteral @ org-dartlang-testcase:///generic_primary_constructor.dart:29:6 -> ListConstant(const >[const E1{E1.b: 1, E1.c: 0, E1.d: 1, E1.f: int, _Enum.index: 0, _Enum._name: "a"}]) -Evaluated: ConstructorInvocation @ org-dartlang-testcase:///generic_primary_constructor.dart:41:3 -> InstanceConstant(const E2{E2.b: 1, E2.d: null, E2.e: null, E2.f: null, _Enum.index: 0, _Enum._name: "a"}) -Evaluated: ListLiteral @ org-dartlang-testcase:///generic_primary_constructor.dart:40:6 -> ListConstant(const >[const E2{E2.b: 1, E2.d: null, E2.e: null, E2.f: null, _Enum.index: 0, _Enum._name: "a"}]) -Extra constant evaluation: evaluated: 25, effectively constant: 4 +Evaluated: ConstructorInvocation @ org-dartlang-testcase:///generic_primary_constructor.dart:41:3 -> InstanceConstant(const E2{E2.b: 1, E2.d: 0, E2.e: 1, E2.f: int, _Enum.index: 0, _Enum._name: "a"}) +Evaluated: ListLiteral @ org-dartlang-testcase:///generic_primary_constructor.dart:40:6 -> ListConstant(const >[const E2{E2.b: 1, E2.d: 0, E2.e: 1, E2.f: int, _Enum.index: 0, _Enum._name: "a"}]) +Extra constant evaluation: evaluated: 28, effectively constant: 4 diff --git a/pkg/front_end/testcases/textual_outline.status b/pkg/front_end/testcases/textual_outline.status index 8317505b183..7f23ea2d91d 100644 --- a/pkg/front_end/testcases/textual_outline.status +++ b/pkg/front_end/testcases/textual_outline.status @@ -20,6 +20,7 @@ patterns/pattern_variable_final: FormatterCrash primary_constructors/body_without_primary: FormatterCrash primary_constructors/class_primary_constructor: FormatterCrash primary_constructors/class_primary_declaring_parameters: FormatterCrash +primary_constructors/const_parameters: FormatterCrash primary_constructors/const_class: FormatterCrash primary_constructors/duplicate_initialization: FormatterCrash primary_constructors/enum_primary_constructor: FormatterCrash