blob: 61cd1497dfe9eb1087034894336e4b35b6b11ece [file] [log] [blame]
// Copyright (c) 2021, 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.
library fasta.class_hierarchy_builder;
import 'package:kernel/ast.dart';
import 'package:kernel/src/legacy_erasure.dart';
import '../../source/source_class_builder.dart';
import 'class_member.dart';
import 'members_builder.dart';
import 'members_node.dart';
abstract class DelayedCheck {
void check(ClassMembersBuilder membersBuilder);
}
class DelayedOverrideCheck implements DelayedCheck {
final SourceClassBuilder _classBuilder;
final ClassMember _declaredMember;
final Set<ClassMember> _overriddenMembers;
DelayedOverrideCheck(
this._classBuilder, this._declaredMember, this._overriddenMembers);
@override
void check(ClassMembersBuilder membersBuilder) {
Member declaredMember = _declaredMember.getMember(membersBuilder);
/// If [_declaredMember] is a class member that is declared in an opt-in
/// library but inherited to [_classBuilder] through an opt-out class then
/// we need to apply legacy erasure to the declared type to get the
/// inherited type.
///
/// For interface members this is handled by member signatures but since
/// these are abstract they will never be the inherited class member.
///
/// For instance:
///
/// // Opt in:
/// class Super {
/// int extendedMethod(int i, {required int j}) => i;
/// }
/// class Mixin {
/// int mixedInMethod(int i, {required int j}) => i;
/// }
/// // Opt out:
/// class Legacy extends Super with Mixin {}
/// // Opt in:
/// class Class extends Legacy {
/// // Valid overrides since the type of `Legacy.extendedMethod` is
/// // `int* Function(int*, {int* j})`.
/// int? extendedMethod(int? i, {int? j}) => i;
/// // Valid overrides since the type of `Legacy.mixedInMethod` is
/// // `int* Function(int*, {int* j})`.
/// int? mixedInMethod(int? i, {int? j}) => i;
/// }
///
bool declaredNeedsLegacyErasure =
needsLegacyErasure(_classBuilder.cls, declaredMember.enclosingClass!);
void callback(Member interfaceMember, bool isSetter) {
_classBuilder.checkOverride(membersBuilder.hierarchyBuilder.types,
membersBuilder, declaredMember, interfaceMember, isSetter, callback,
isInterfaceCheck: !_classBuilder.isMixinApplication,
declaredNeedsLegacyErasure: declaredNeedsLegacyErasure);
}
for (ClassMember overriddenMember in _overriddenMembers) {
callback(
overriddenMember.getMember(membersBuilder), _declaredMember.isSetter);
}
}
}
class DelayedGetterSetterCheck implements DelayedCheck {
final SourceClassBuilder classBuilder;
final ClassMember getter;
final ClassMember setter;
const DelayedGetterSetterCheck(this.classBuilder, this.getter, this.setter);
@override
void check(ClassMembersBuilder membersBuilder) {
classBuilder.checkGetterSetter(membersBuilder.hierarchyBuilder.types,
getter.getMember(membersBuilder), setter.getMember(membersBuilder));
}
}
class DelayedTypeComputation {
final ClassMembersNodeBuilder builder;
final ClassMember declaredMember;
final Set<ClassMember> overriddenMembers;
bool _computed = false;
DelayedTypeComputation(
this.builder, this.declaredMember, this.overriddenMembers)
: assert(declaredMember.isSourceDeclaration);
void compute(ClassMembersBuilder membersBuilder) {
if (_computed) return;
declaredMember.inferType(membersBuilder);
_computed = true;
if (declaredMember.isField) {
builder.inferFieldSignature(
membersBuilder, declaredMember, overriddenMembers);
} else if (declaredMember.isGetter) {
builder.inferGetterSignature(
membersBuilder, declaredMember, overriddenMembers);
} else if (declaredMember.isSetter) {
builder.inferSetterSignature(
membersBuilder, declaredMember, overriddenMembers);
} else {
builder.inferMethodSignature(
membersBuilder, declaredMember, overriddenMembers);
}
}
@override
String toString() => 'DelayedTypeComputation('
'${builder.classBuilder.name},$declaredMember,$overriddenMembers)';
}