blob: 22b48629126bd2a71e0e927064401a5b878d1510 [file] [log] [blame]
// Copyright (c) 2016, 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.named_type_builder;
import 'package:kernel/ast.dart';
import 'package:kernel/class_hierarchy.dart';
import 'package:kernel/src/legacy_erasure.dart';
import 'package:kernel/src/unaliasing.dart';
import '../fasta_codes.dart'
show
LocatedMessage,
Message,
Severity,
Template,
messageNotATypeContext,
messageTypeVariableInStaticContext,
messageTypedefCause,
noLength,
templateExtendingRestricted,
templateNotAType,
templateSupertypeIsIllegal,
templateSupertypeIsIllegalAliased,
templateSupertypeIsNullableAliased,
templateSupertypeIsTypeVariable,
templateTypeArgumentMismatch,
templateTypeArgumentsOnTypeVariable,
templateTypeNotFound;
import '../identifiers.dart' show Identifier, QualifiedName, flattenName;
import '../kernel/implicit_field_type.dart';
import '../problems.dart' show unhandled;
import '../scope.dart';
import '../source/source_library_builder.dart';
import '../uris.dart';
import 'builder.dart';
import 'builtin_type_declaration_builder.dart';
import 'class_builder.dart';
import 'invalid_type_declaration_builder.dart';
import 'library_builder.dart';
import 'nullability_builder.dart';
import 'prefix_builder.dart';
import 'type_alias_builder.dart';
import 'type_builder.dart';
import 'type_declaration_builder.dart';
import 'type_variable_builder.dart';
import 'void_type_declaration_builder.dart';
/// Enum used to determine how instance type variable access is allowed.
enum InstanceTypeVariableAccessState {
/// Instance type variable access is allowed.
///
/// This is used for valid references to instance type variables, like
///
/// class Class<T> {
/// void instanceMethod(T t) {}
/// }
Allowed,
/// Instance type variable access is disallowed and results in a compile-time
/// error.
///
/// This is used for static references to instance type variables, like
///
/// class Class<T> {
/// static void staticMethod(T t) {}
/// }
///
/// The type is resolved as an [InvalidType].
Disallowed,
/// Instance type variable access is invalid since it occurs in an invalid
/// context. The occurrence _doesn't_ result in a compile-time error.
///
/// This is used for references to instance type variables where they might
/// be valid if the context where, like
///
/// class Extension<T> {
/// T field; // Instance extension fields are not allowed.
/// }
///
/// The type is resolved as an [InvalidType].
Invalid,
/// Instance type variable access is unexpected and results in an assertion
/// failure.
///
/// This is used for [NamedTypeBuilder]s for known non-type variable types,
/// like for `Object` and `String`.
Unexpected,
}
abstract class NamedTypeBuilder extends TypeBuilder {
@override
final Object name;
List<TypeBuilder>? arguments;
@override
final NullabilityBuilder nullabilityBuilder;
@override
final Uri? fileUri;
@override
final int? charOffset;
TypeDeclarationBuilder? _declaration;
final InstanceTypeVariableAccessState _instanceTypeVariableAccess;
final bool _performTypeCanonicalization;
final bool hasExplicitTypeArguments;
factory NamedTypeBuilder(Object name, NullabilityBuilder nullabilityBuilder,
{List<TypeBuilder>? arguments,
Uri? fileUri,
int? charOffset,
required InstanceTypeVariableAccessState instanceTypeVariableAccess,
bool performTypeCanonicalization: false}) {
bool isExplicit = true;
if (arguments != null) {
for (TypeBuilder argument in arguments) {
if (!argument.isExplicit) {
isExplicit = false;
}
}
}
return isExplicit
? new _ExplicitNamedTypeBuilder(name, nullabilityBuilder,
arguments: arguments,
fileUri: fileUri,
charOffset: charOffset,
instanceTypeVariableAccess: instanceTypeVariableAccess,
performTypeCanonicalization: performTypeCanonicalization)
: new _InferredNamedTypeBuilder(name, nullabilityBuilder,
arguments: arguments,
fileUri: fileUri,
charOffset: charOffset,
instanceTypeVariableAccess: instanceTypeVariableAccess,
performTypeCanonicalization: performTypeCanonicalization);
}
NamedTypeBuilder._(
{required this.name,
required this.nullabilityBuilder,
this.arguments,
this.fileUri,
this.charOffset,
required InstanceTypeVariableAccessState instanceTypeVariableAccess,
bool performTypeCanonicalization: false,
TypeDeclarationBuilder? declaration})
: assert(name is String || name is QualifiedName),
this._instanceTypeVariableAccess = instanceTypeVariableAccess,
this._performTypeCanonicalization = performTypeCanonicalization,
this.hasExplicitTypeArguments = arguments != null,
this._declaration = declaration;
factory NamedTypeBuilder.forDartType(
DartType type,
TypeDeclarationBuilder _declaration,
NullabilityBuilder nullabilityBuilder,
{List<TypeBuilder>? arguments}) = _ExplicitNamedTypeBuilder.forDartType;
factory NamedTypeBuilder.fromTypeDeclarationBuilder(
TypeDeclarationBuilder declaration, NullabilityBuilder nullabilityBuilder,
{List<TypeBuilder>? arguments,
Uri? fileUri,
int? charOffset,
required InstanceTypeVariableAccessState instanceTypeVariableAccess,
DartType? type}) = _ExplicitNamedTypeBuilder.fromTypeDeclarationBuilder;
factory NamedTypeBuilder.forInvalidType(String name,
NullabilityBuilder nullabilityBuilder, LocatedMessage message,
{List<LocatedMessage>? context}) =
_ExplicitNamedTypeBuilder.forInvalidType;
@override
TypeDeclarationBuilder? get declaration => _declaration;
@override
bool get isVoidType => declaration is VoidTypeDeclarationBuilder;
void bind(LibraryBuilder libraryBuilder, TypeDeclarationBuilder declaration) {
_declaration = declaration.origin;
_check(libraryBuilder);
}
String get nameText {
if (name is Identifier) {
Identifier identifier = name as Identifier;
return identifier.name;
} else {
assert(name is String);
return name as String;
}
}
int get nameOffset {
if (name is Identifier) {
Identifier identifier = name as Identifier;
return identifier.charOffset;
}
return charOffset!;
}
int get nameLength {
return nameText.length;
}
void resolveIn(
Scope scope, int charOffset, Uri fileUri, LibraryBuilder library) {
if (_declaration != null) return;
final Object name = this.name;
Builder? member;
if (name is QualifiedName) {
Object qualifier = name.qualifier;
String prefixName = flattenName(qualifier, charOffset, fileUri);
Builder? prefix = scope.lookup(prefixName, charOffset, fileUri);
if (prefix is PrefixBuilder) {
member = prefix.lookup(name.name, name.charOffset, fileUri);
}
} else if (name is String) {
member = scope.lookup(name, charOffset, fileUri);
} else {
unhandled("${name.runtimeType}", "resolveIn", charOffset, fileUri);
}
if (member is TypeDeclarationBuilder) {
bind(library, member);
} else {
Template<Message Function(String name)> template =
member == null ? templateTypeNotFound : templateNotAType;
String flatName = flattenName(name, charOffset, fileUri);
int length = name is Identifier
? name.endCharOffset - charOffset
: flatName.length;
Message message;
List<LocatedMessage>? context;
if (member == null) {
template = templateTypeNotFound;
message = template.withArguments(flatName);
} else {
template = templateNotAType;
context = <LocatedMessage>[
messageNotATypeContext.withLocation(
member.fileUri!,
member.charOffset,
name is Identifier ? name.name.length : "$name".length)
];
message = template.withArguments(flatName);
}
library.addProblem(message, charOffset, length, fileUri,
context: context);
TypeDeclarationBuilder declaration = buildInvalidTypeDeclarationBuilder(
message.withLocation(fileUri, charOffset, length),
context: context);
bind(library, declaration);
}
}
void _check(LibraryBuilder library) {
if (_declaration is InvalidTypeDeclarationBuilder) {
return;
}
if (arguments != null) {
if (_declaration!.isTypeVariable) {
String typeName = nameText;
int typeNameOffset = nameOffset;
Message message =
templateTypeArgumentsOnTypeVariable.withArguments(typeName);
library.addProblem(message, typeNameOffset, typeName.length, fileUri);
// TODO(johnniwinther): Should we retain the declaration to support
// additional errors?
_declaration = buildInvalidTypeDeclarationBuilder(
message.withLocation(fileUri!, typeNameOffset, typeName.length));
} else if (arguments!.length != declaration!.typeVariablesCount) {
int typeNameLength = nameLength;
int typeNameOffset = nameOffset;
Message message = templateTypeArgumentMismatch
.withArguments(declaration!.typeVariablesCount);
library.addProblem(message, typeNameOffset, typeNameLength, fileUri);
_declaration = buildInvalidTypeDeclarationBuilder(
message.withLocation(fileUri!, typeNameOffset, typeNameLength));
}
}
if (_declaration!.isExtension &&
library is SourceLibraryBuilder &&
!library.libraryFeatures.extensionTypes.isEnabled) {
int typeNameLength = nameLength;
int typeNameOffset = nameOffset;
Message message = library.reportFeatureNotEnabled(
library.libraryFeatures.extensionTypes,
fileUri!,
typeNameOffset,
typeNameLength);
_declaration = buildInvalidTypeDeclarationBuilder(
message.withLocation(fileUri!, typeNameOffset, typeNameLength));
} else if (_declaration!.isTypeVariable) {
TypeVariableBuilder typeParameterBuilder =
_declaration as TypeVariableBuilder;
if (typeParameterBuilder.kind == TypeVariableKind.classMixinOrEnum ||
typeParameterBuilder.kind == TypeVariableKind.extension ||
typeParameterBuilder.kind == TypeVariableKind.extensionSynthesized) {
switch (_instanceTypeVariableAccess) {
case InstanceTypeVariableAccessState.Disallowed:
int typeNameLength = nameLength;
int typeNameOffset = nameOffset;
Message message = messageTypeVariableInStaticContext;
library.addProblem(
message, typeNameOffset, typeNameLength, fileUri);
_declaration = buildInvalidTypeDeclarationBuilder(
message.withLocation(fileUri!, typeNameOffset, typeNameLength));
return;
case InstanceTypeVariableAccessState.Invalid:
int typeNameLength = nameLength;
int typeNameOffset = nameOffset;
Message message = messageTypeVariableInStaticContext;
_declaration = buildInvalidTypeDeclarationBuilder(
message.withLocation(fileUri!, typeNameOffset, typeNameLength));
return;
case InstanceTypeVariableAccessState.Unexpected:
assert(false,
"Unexpected instance type variable $typeParameterBuilder");
break;
case InstanceTypeVariableAccessState.Allowed:
break;
}
}
}
}
@override
String get debugName => "NamedTypeBuilder";
@override
StringBuffer printOn(StringBuffer buffer) {
buffer.write(flattenName(name, charOffset ?? TreeNode.noOffset, fileUri));
if (arguments?.isEmpty ?? true) return buffer;
buffer.write("<");
bool first = true;
for (TypeBuilder t in arguments!) {
if (!first) buffer.write(", ");
first = false;
t.printOn(buffer);
}
buffer.write(">");
nullabilityBuilder.writeNullabilityOn(buffer);
return buffer;
}
InvalidTypeDeclarationBuilder buildInvalidTypeDeclarationBuilder(
LocatedMessage message,
{List<LocatedMessage>? context}) {
// TODO(ahe): Consider if it makes sense to pass a QualifiedName to
// InvalidTypeBuilder?
return new InvalidTypeDeclarationBuilder(
flattenName(name, message.charOffset, message.uri), message,
context: context);
}
Supertype? _handleInvalidSupertype(LibraryBuilder library) {
Template<Message Function(String name)> template =
declaration!.isTypeVariable
? templateSupertypeIsTypeVariable
: templateSupertypeIsIllegal;
library.addProblem(template.withArguments(fullNameForErrors), charOffset!,
noLength, fileUri);
return null;
}
Supertype? _handleInvalidAliasedSupertype(
LibraryBuilder library, TypeAliasBuilder aliasBuilder, DartType type) {
// Don't report the error in case of InvalidType. An error has already been
// reported in this case.
if (type is InvalidType) return null;
Message message;
if (declaration!.isTypeVariable) {
message =
templateSupertypeIsTypeVariable.withArguments(fullNameForErrors);
} else
// ignore: unnecessary_null_comparison
if (type != null && type.nullability == Nullability.nullable) {
message = templateSupertypeIsNullableAliased.withArguments(
fullNameForErrors, type, library.isNonNullableByDefault);
} else {
message = templateSupertypeIsIllegalAliased.withArguments(
fullNameForErrors, type, library.isNonNullableByDefault);
}
library.addProblem(message, charOffset!, noLength, fileUri, context: [
messageTypedefCause.withLocation(
aliasBuilder.fileUri, aliasBuilder.charOffset, noLength),
]);
return null;
}
DartType _buildInternal(
LibraryBuilder library, TypeUse typeUse, ClassHierarchyBase? hierarchy) {
DartType aliasedType = _buildAliasedInternal(library, typeUse, hierarchy);
return unalias(aliasedType,
legacyEraseAliases:
!_performTypeCanonicalization && !library.isNonNullableByDefault);
}
@override
DartType buildAliased(
LibraryBuilder library, TypeUse typeUse, ClassHierarchyBase? hierarchy) {
assert(hierarchy != null || isExplicit, "Cannot build $this.");
return _buildAliasedInternal(library, typeUse, hierarchy);
}
DartType _buildAliasedInternal(
LibraryBuilder library, TypeUse typeUse, ClassHierarchyBase? hierarchy) {
assert(declaration != null, "Declaration has not been resolved on $this.");
return declaration!.buildAliasedType(
library,
nullabilityBuilder,
arguments,
typeUse,
fileUri ?? missingUri,
charOffset ?? TreeNode.noOffset,
hierarchy,
hasExplicitTypeArguments: hasExplicitTypeArguments);
}
@override
Supertype? buildSupertype(LibraryBuilder library) {
TypeDeclarationBuilder declaration = this.declaration!;
if (declaration is ClassBuilder) {
if (declaration.isNullClass) {
if (!library.mayImplementRestrictedTypes) {
library.addProblem(
templateExtendingRestricted.withArguments(declaration.name),
charOffset!,
noLength,
fileUri);
}
}
DartType type = build(library, TypeUse.superType);
if (type is InterfaceType) {
if (!library.isNonNullableByDefault) {
// This "normalizes" type argument `Never*` to `Null`.
type = legacyErasure(type) as InterfaceType;
}
return new Supertype(type.classNode, type.typeArguments);
} else if (type is FutureOrType) {
return new Supertype(declaration.cls, [type.typeArgument]);
} else if (type is NullType) {
return new Supertype(declaration.cls, []);
}
} else if (declaration is TypeAliasBuilder) {
TypeAliasBuilder aliasBuilder = declaration;
DartType type = build(library, TypeUse.superType);
if (type is InterfaceType && type.nullability != Nullability.nullable) {
return new Supertype(type.classNode, type.typeArguments);
} else if (type is NullType) {
// Even though Null is disallowed as a supertype, ClassHierarchyBuilder
// still expects it to be built to the respective InterfaceType
// referencing the deprecated class.
// TODO(cstefantsova): Remove the dependency on the deprecated Null
// class from ClassHierarchyBuilder.
TypeDeclarationBuilder? unaliasedDeclaration = this.declaration;
// The following code assumes that the declaration is a TypeAliasBuilder
// that through a chain of other TypeAliasBuilders (possibly, the chain
// length is 0) references a ClassBuilder of the Null class. Otherwise,
// it won't produce the NullType on the output.
while (unaliasedDeclaration is TypeAliasBuilder) {
unaliasedDeclaration = unaliasedDeclaration.type.declaration;
assert(unaliasedDeclaration != null);
}
assert(unaliasedDeclaration is ClassBuilder &&
unaliasedDeclaration.name == "Null");
return new Supertype(
(unaliasedDeclaration as ClassBuilder).cls, const <DartType>[]);
} else if (type is FutureOrType) {
// Even though FutureOr is disallowed as a supertype,
// ClassHierarchyBuilder still expects it to be built to the respective
// InterfaceType referencing the deprecated class. In contrast with
// Null, it doesn't surface as an error due to FutureOr class not having
// any inheritable members.
// TODO(cstefantsova): Remove the dependency on the deprecated FutureOr
// class from ClassHierarchyBuilder.
TypeDeclarationBuilder? unaliasedDeclaration = this.declaration;
// The following code assumes that the declaration is a TypeAliasBuilder
// that through a chain of other TypeAliasBuilders (possibly, the chain
// length is 0) references a ClassBuilder of the FutureOr class.
// Otherwise, it won't produce the FutureOrType on the output.
while (unaliasedDeclaration is TypeAliasBuilder) {
unaliasedDeclaration = unaliasedDeclaration.type.declaration;
assert(unaliasedDeclaration != null);
}
assert(unaliasedDeclaration is ClassBuilder &&
unaliasedDeclaration.name == "FutureOr");
return new Supertype((unaliasedDeclaration as ClassBuilder).cls,
<DartType>[type.typeArgument]);
}
return _handleInvalidAliasedSupertype(library, aliasBuilder, type);
} else if (declaration is InvalidTypeDeclarationBuilder) {
library.addProblem(
declaration.message.messageObject,
declaration.message.charOffset,
declaration.message.length,
declaration.message.uri,
severity: Severity.error);
return null;
}
return _handleInvalidSupertype(library);
}
@override
Supertype? buildMixedInType(LibraryBuilder library) {
TypeDeclarationBuilder declaration = this.declaration!;
if (declaration is ClassBuilder) {
return declaration.buildMixedInType(library, arguments);
} else if (declaration is TypeAliasBuilder) {
TypeAliasBuilder aliasBuilder = declaration;
DartType type = build(library, TypeUse.mixedInType);
if (type is InterfaceType && type.nullability != Nullability.nullable) {
return new Supertype(type.classNode, type.typeArguments);
}
return _handleInvalidAliasedSupertype(library, aliasBuilder, type);
} else if (declaration is InvalidTypeDeclarationBuilder) {
library.addProblem(
declaration.message.messageObject,
declaration.message.charOffset,
declaration.message.length,
declaration.message.uri,
severity: Severity.error);
return null;
}
return _handleInvalidSupertype(library);
}
@override
TypeBuilder subst(Map<TypeVariableBuilder, TypeBuilder> substitution) {
TypeBuilder? result = substitution[declaration];
if (result != null) {
assert(declaration is TypeVariableBuilder);
return result;
} else if (this.arguments != null) {
List<TypeBuilder>? arguments;
int i = 0;
for (TypeBuilder argument in this.arguments!) {
TypeBuilder type = argument.subst(substitution);
if (type != argument) {
arguments ??= this.arguments!.toList();
arguments[i] = type;
}
i++;
}
if (arguments != null) {
return new NamedTypeBuilder.fromTypeDeclarationBuilder(
declaration!, nullabilityBuilder,
arguments: arguments,
fileUri: fileUri,
charOffset: charOffset,
instanceTypeVariableAccess: _instanceTypeVariableAccess);
}
}
return this;
}
@override
NamedTypeBuilder clone(
List<NamedTypeBuilder> newTypes,
SourceLibraryBuilder contextLibrary,
TypeParameterScopeBuilder contextDeclaration) {
List<TypeBuilder>? clonedArguments;
if (arguments != null) {
clonedArguments =
new List<TypeBuilder>.generate(arguments!.length, (int i) {
return arguments![i]
.clone(newTypes, contextLibrary, contextDeclaration);
}, growable: false);
}
NamedTypeBuilder newType = new NamedTypeBuilder(name, nullabilityBuilder,
arguments: clonedArguments,
fileUri: fileUri,
charOffset: charOffset,
instanceTypeVariableAccess: _instanceTypeVariableAccess);
if (declaration is BuiltinTypeDeclarationBuilder) {
newType._declaration = declaration;
} else {
newTypes.add(newType);
}
return newType;
}
@override
NamedTypeBuilder withNullabilityBuilder(
NullabilityBuilder nullabilityBuilder) {
return new NamedTypeBuilder.fromTypeDeclarationBuilder(
declaration!, nullabilityBuilder,
arguments: arguments,
fileUri: fileUri,
charOffset: charOffset,
instanceTypeVariableAccess: _instanceTypeVariableAccess);
}
/// Returns a copy of this named type using the provided type [arguments]
/// instead of the original type arguments.
NamedTypeBuilder withArguments(List<TypeBuilder> arguments) {
if (_declaration != null) {
return new NamedTypeBuilder.fromTypeDeclarationBuilder(
_declaration!, nullabilityBuilder,
arguments: arguments,
fileUri: fileUri,
charOffset: charOffset,
instanceTypeVariableAccess: _instanceTypeVariableAccess);
} else {
return new NamedTypeBuilder(name, nullabilityBuilder,
arguments: arguments,
fileUri: fileUri,
charOffset: charOffset,
instanceTypeVariableAccess: _instanceTypeVariableAccess);
}
}
}
/// A named type that is defined without the need for type inference.
///
/// This is the normal function type whose type arguments are either explicit or
/// omitted.
class _ExplicitNamedTypeBuilder extends NamedTypeBuilder {
DartType? _type;
_ExplicitNamedTypeBuilder(Object name, NullabilityBuilder nullabilityBuilder,
{List<TypeBuilder>? arguments,
Uri? fileUri,
int? charOffset,
required InstanceTypeVariableAccessState instanceTypeVariableAccess,
bool performTypeCanonicalization: false})
: super._(
name: name,
nullabilityBuilder: nullabilityBuilder,
arguments: arguments,
fileUri: fileUri,
charOffset: charOffset,
instanceTypeVariableAccess: instanceTypeVariableAccess,
performTypeCanonicalization: performTypeCanonicalization);
_ExplicitNamedTypeBuilder.forDartType(DartType type,
TypeDeclarationBuilder declaration, NullabilityBuilder nullabilityBuilder,
{List<TypeBuilder>? arguments})
: _type = type,
super._(
declaration: declaration,
name: declaration.name,
nullabilityBuilder: nullabilityBuilder,
arguments: arguments,
instanceTypeVariableAccess:
InstanceTypeVariableAccessState.Unexpected,
fileUri: null,
charOffset: null,
performTypeCanonicalization: false);
_ExplicitNamedTypeBuilder.fromTypeDeclarationBuilder(
TypeDeclarationBuilder declaration, NullabilityBuilder nullabilityBuilder,
{List<TypeBuilder>? arguments,
Uri? fileUri,
int? charOffset,
required InstanceTypeVariableAccessState instanceTypeVariableAccess,
DartType? type})
: this._type = type,
super._(
name: declaration.name,
declaration: declaration,
nullabilityBuilder: nullabilityBuilder,
arguments: arguments,
fileUri: fileUri,
charOffset: charOffset,
performTypeCanonicalization: false,
instanceTypeVariableAccess: instanceTypeVariableAccess);
_ExplicitNamedTypeBuilder.forInvalidType(String name,
NullabilityBuilder nullabilityBuilder, LocatedMessage message,
{List<LocatedMessage>? context})
: _type = const InvalidType(),
super._(
name: name,
nullabilityBuilder: nullabilityBuilder,
declaration: new InvalidTypeDeclarationBuilder(name, message,
context: context),
fileUri: message.uri,
charOffset: message.charOffset,
instanceTypeVariableAccess:
InstanceTypeVariableAccessState.Unexpected,
performTypeCanonicalization: false);
@override
bool get isExplicit => true;
@override
DartType build(LibraryBuilder library, TypeUse typeUse,
{ClassHierarchyBase? hierarchy}) {
return _type ??= _buildInternal(library, typeUse, hierarchy);
}
}
/// A named type that needs type inference to be fully defined.
///
/// This occurs through macros where type arguments can be defined in terms of
/// inferred types, making this type indirectly depend on type inference.
class _InferredNamedTypeBuilder extends NamedTypeBuilder
with InferableTypeBuilderMixin {
_InferredNamedTypeBuilder(Object name, NullabilityBuilder nullabilityBuilder,
{List<TypeBuilder>? arguments,
Uri? fileUri,
int? charOffset,
required InstanceTypeVariableAccessState instanceTypeVariableAccess,
bool performTypeCanonicalization: false})
: super._(
name: name,
nullabilityBuilder: nullabilityBuilder,
arguments: arguments,
fileUri: fileUri,
charOffset: charOffset,
instanceTypeVariableAccess: instanceTypeVariableAccess,
performTypeCanonicalization: performTypeCanonicalization);
@override
bool get isExplicit => false;
@override
DartType build(LibraryBuilder library, TypeUse typeUse,
{ClassHierarchyBase? hierarchy}) {
if (hasType) {
return type;
} else if (hierarchy != null) {
return registerType(_buildInternal(library, typeUse, hierarchy));
} else {
InferableTypeUse inferableTypeUse =
new InferableTypeUse(library as SourceLibraryBuilder, this, typeUse);
library.registerInferableType(inferableTypeUse);
return new InferredType.fromInferableTypeUse(inferableTypeUse);
}
}
}