inferProviderType function
DartType?
inferProviderType(
- DartObject provider,
- DartObject token
Returns the CompileTypeMetadata appropriate for T
in Provider<T>
.
Implementation
DartType? inferProviderType(DartObject provider, DartObject token) {
// Complexity of code is two-fold:
//
// 1. The analyzer has subtle top-level inference bugs. Sometimes the <T>
// may be reported as dynamic or Object, when otherwise it would be
// (correctly) inferred as a the T from an existing OpaqueToken<T>.
// https://github.com/dart-lang/sdk/issues/32290
//
// 2. In the case of MultiToken<T>, the token type strictly speaking is
// List<T>, but we want to encode it as a <T> with the "multi" flag
// set. This means that providers that use multi tokens need a special
// case.
//
// Check for MultiToken<T>.
final tokenType = token.type;
if (tokenType != null && $MultiToken.isAssignableFromType(tokenType)) {
if (tokenType is InterfaceType && $MultiToken.isExactlyType(tokenType)) {
return tokenType.typeArguments.first;
}
// Check for a _custom_ MultiToken<T>
final tokenTypeClass = tokenType.element;
if (tokenTypeClass is ClassElement) {
var supertype = tokenTypeClass.supertype!;
if (!$MultiToken.isExactlyType(supertype)) {
// When we start using angular_compiler to resolve all of the time
// remove this message, since we already validate there.
throw BuildError.forElement(
tokenType.element!,
'A sub-type of OpaqueToken must directly extend OpaqueToken or '
'MultiToken, and cannot extend another class that in turn extends '
'OpaqueToken or MultiToken.\n\n'
'We may loosten these restrictions in the future. See: '
'https://github.com/angulardart/angular/issues/899');
}
return supertype.typeArguments.first;
}
}
// Lookup Inferred Type (i.e. the <T> recorded for Provider<T>).
var providerType = provider.type;
if (providerType is InterfaceType) {
final providerOfTArgs = providerType.typeArguments;
if (providerOfTArgs.isNotEmpty) {
final genericType = providerOfTArgs.first;
// If type inference fails it might resolve to dynamic or Object.
if (!genericType.isDynamic && !genericType.isDartCoreObject) {
return genericType;
}
}
}
// Fallback and try to extract from OpaqueToken<T>.
if (tokenType is InterfaceType &&
$OpaqueToken.isAssignableFromType(tokenType) &&
// Only apply "auto inference" to "new-type" Providers like
// Value, Class, Existing, FactoryProvider.
!$Provider.isExactlyType(provider.type!) &&
tokenType.typeArguments.isNotEmpty) {
final opaqueTokenOfT = tokenType.typeArguments.first;
if (!opaqueTokenOfT.isDynamic) {
return opaqueTokenOfT;
}
}
// We failed to find any type we can use. This will mean "dynamic" elsewhere.
return null;
}