@@ -58,7 +58,28 @@ public INamedTypeSymbol Get(SpecialType type)
5858 return _compilation . GetSpecialType ( type ) ;
5959 }
6060
61+ /// <summary>
62+ /// Returns the type symbol for the specified well-known type, or throws if the type cannot be found.
63+ /// </summary>
6164 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 )
6283 {
6384 var index = ( int ) type ;
6485 var symbol = _lazyWellKnownTypes [ index ] ;
@@ -69,16 +90,22 @@ public INamedTypeSymbol Get(WellKnownTypeData.WellKnownType type)
6990
7091 // Symbol hasn't been added to the cache yet.
7192 // Resolve symbol from name, cache, and return.
72- return GetAndCache ( index ) ;
93+ return GetAndCache ( index , throwOnNotFound ) ;
7394 }
7495
75- private INamedTypeSymbol GetAndCache ( int index )
96+ private INamedTypeSymbol GetAndCache ( int index , bool throwOnNotFound )
7697 {
7798 var result = GetTypeByMetadataNameInTargetAssembly ( WellKnownTypeData . WellKnownTypeNames [ index ] ) ;
78- if ( result == null )
99+
100+ if ( result == null && throwOnNotFound )
79101 {
80102 throw new InvalidOperationException ( $ "Failed to resolve well-known type '{ WellKnownTypeData . WellKnownTypeNames [ index ] } '.") ;
81103 }
104+ else
105+ {
106+ result ??= _compilation . GetTypeByMetadataName ( typeof ( MissingType ) . FullName ! ) ! ;
107+ }
108+
82109 Interlocked . CompareExchange ( ref _lazyWellKnownTypes [ index ] , result , null ) ;
83110
84111 // GetTypeByMetadataName should always return the same instance for a name.
@@ -159,4 +186,6 @@ public static bool Implements(ITypeSymbol? type, ITypeSymbol interfaceType)
159186 }
160187 return false ;
161188 }
189+
190+ internal class MissingType { }
162191}
0 commit comments