@@ -19,7 +19,6 @@ public static WellKnownTypes GetOrCreate(Compilation compilation) =>
1919
2020 private readonly INamedTypeSymbol ? [ ] _lazyWellKnownTypes ;
2121 private readonly Compilation _compilation ;
22- private readonly INamedTypeSymbol _missingTypeSymbol ;
2322
2423 static WellKnownTypes ( )
2524 {
@@ -52,15 +51,35 @@ private WellKnownTypes(Compilation compilation)
5251 {
5352 _lazyWellKnownTypes = new INamedTypeSymbol ? [ WellKnownTypeData . WellKnownTypeNames . Length ] ;
5453 _compilation = compilation ;
55- _missingTypeSymbol = compilation . GetTypeByMetadataName ( typeof ( MissingType ) . FullName ! ) ! ;
5654 }
5755
5856 public INamedTypeSymbol Get ( SpecialType type )
5957 {
6058 return _compilation . GetSpecialType ( type ) ;
6159 }
6260
61+ /// <summary>
62+ /// Returns the type symbol for the specified well-known type, or throws if the type cannot be found.
63+ /// </summary>
6364 public INamedTypeSymbol Get ( WellKnownTypeData . WellKnownType type )
65+ {
66+ return Get ( type , throwOnNotFound : true ) ;
67+ }
68+
69+ /// <summary>
70+ /// Returns the type symbol for the specified well-known type, or a special marker type symbol if the type cannot be found.
71+ /// </summary>
72+ /// <remarks>
73+ /// We use a special marker type for cases where some types can be legitimately missing.
74+ /// E.g. The Microsoft.Extensions.Validation source generator checks against some types
75+ /// from the shared framework which are missing in Blazor WebAssembly SDK projects.
76+ /// </remarks>
77+ public INamedTypeSymbol GetOptional ( WellKnownTypeData . WellKnownType type )
78+ {
79+ return Get ( type , throwOnNotFound : false ) ;
80+ }
81+
82+ private INamedTypeSymbol Get ( WellKnownTypeData . WellKnownType type , bool throwOnNotFound )
6483 {
6584 var index = ( int ) type ;
6685 var symbol = _lazyWellKnownTypes [ index ] ;
@@ -71,12 +90,22 @@ public INamedTypeSymbol Get(WellKnownTypeData.WellKnownType type)
7190
7291 // Symbol hasn't been added to the cache yet.
7392 // Resolve symbol from name, cache, and return.
74- return GetAndCache ( index ) ;
93+ return GetAndCache ( index , throwOnNotFound ) ;
7594 }
7695
77- private INamedTypeSymbol GetAndCache ( int index )
96+ private INamedTypeSymbol GetAndCache ( int index , bool throwOnNotFound )
7897 {
79- var result = GetTypeByMetadataNameInTargetAssembly ( WellKnownTypeData . WellKnownTypeNames [ index ] ) ?? _missingTypeSymbol ;
98+ var result = GetTypeByMetadataNameInTargetAssembly ( WellKnownTypeData . WellKnownTypeNames [ index ] ) ;
99+
100+ if ( result == null && throwOnNotFound )
101+ {
102+ throw new InvalidOperationException ( $ "Failed to resolve well-known type '{ WellKnownTypeData . WellKnownTypeNames [ index ] } '.") ;
103+ }
104+ else
105+ {
106+ result ??= _compilation . GetTypeByMetadataName ( typeof ( MissingType ) . FullName ! ) ! ;
107+ }
108+
80109 Interlocked . CompareExchange ( ref _lazyWellKnownTypes [ index ] , result , null ) ;
81110
82111 // GetTypeByMetadataName should always return the same instance for a name.
0 commit comments