@@ -3027,11 +3027,15 @@ export function createChecker(program: Program, resolver: NameResolver): Checker
30273027 typeof options === "boolean"
30283028 ? { ...defaultSymbolResolutionOptions , resolveDecorators : options }
30293029 : { ...defaultSymbolResolutionOptions , ...( options ?? { } ) } ;
3030- if ( mapper === undefined && resolvedOptions . checkTemplateTypes && referenceSymCache . has ( node ) ) {
3030+ if (
3031+ mapper === undefined &&
3032+ ! resolvedOptions . resolveDeclarationOfTemplate &&
3033+ referenceSymCache . has ( node )
3034+ ) {
30313035 return referenceSymCache . get ( node ) ;
30323036 }
30333037 const sym = resolveTypeReferenceSymInternal ( node , mapper , resolvedOptions ) ;
3034- if ( resolvedOptions . checkTemplateTypes ) {
3038+ if ( ! resolvedOptions . resolveDeclarationOfTemplate ) {
30353039 referenceSymCache . set ( node , sym ) ;
30363040 }
30373041 return sym ;
@@ -3102,6 +3106,12 @@ export function createChecker(program: Program, resolver: NameResolver): Checker
31023106 return undefined ;
31033107 }
31043108 base = aliasedSym ;
3109+ } else if ( ! options . resolveDeclarationOfTemplate && isTemplatedNode ( getSymNode ( base ) ) ) {
3110+ const baseSym = getContainerTemplateSymbol ( base , node . base , mapper ) ;
3111+ if ( ! baseSym ) {
3112+ return undefined ;
3113+ }
3114+ base = baseSym ;
31053115 }
31063116 return resolveMemberInContainer ( base , node , options ) ;
31073117 }
@@ -3226,23 +3236,58 @@ export function createChecker(program: Program, resolver: NameResolver): Checker
32263236
32273237 // Otherwise for templates we need to get the type and retrieve the late bound symbol.
32283238 const aliasType = getTypeForNode ( node as AliasStatementNode , mapper ) ;
3229- if ( isErrorType ( aliasType ) ) {
3239+ return lateBindContainer ( aliasType , aliasSymbol ) ;
3240+ }
3241+
3242+ /** Check case where a template type member is referenced like
3243+ * ```
3244+ * model Foo<T> {t: T}
3245+ * model Test { t: Foo.t } // check `Foo` is correctly used as template
3246+ * ```
3247+ */
3248+ function getContainerTemplateSymbol (
3249+ sym : Sym ,
3250+ node : MemberExpressionNode | IdentifierNode ,
3251+ mapper : TypeMapper | undefined ,
3252+ ) : Sym | undefined {
3253+ if ( pendingResolutions . has ( sym , ResolutionKind . Type ) ) {
3254+ if ( mapper === undefined ) {
3255+ reportCheckerDiagnostic (
3256+ createDiagnostic ( {
3257+ code : "circular-alias-type" ,
3258+ format : { typeName : sym . name } ,
3259+ target : node ,
3260+ } ) ,
3261+ ) ;
3262+ }
3263+ return undefined ;
3264+ }
3265+
3266+ pendingResolutions . start ( sym , ResolutionKind . Type ) ;
3267+ const type = checkTypeReferenceSymbol ( sym , node , mapper ) ;
3268+ pendingResolutions . finish ( sym , ResolutionKind . Type ) ;
3269+
3270+ return lateBindContainer ( type , sym ) ;
3271+ }
3272+
3273+ function lateBindContainer ( type : Type , sym : Sym ) {
3274+ if ( isErrorType ( type ) ) {
32303275 return undefined ;
32313276 }
3232- switch ( aliasType . kind ) {
3277+ switch ( type . kind ) {
32333278 case "Model" :
32343279 case "Interface" :
32353280 case "Union" :
3236- if ( isTemplateInstance ( aliasType ) ) {
3281+ if ( isTemplateInstance ( type ) ) {
32373282 // this is an alias for some instantiation, so late-bind the instantiation
3238- lateBindMemberContainer ( aliasType ) ;
3239- return aliasType . symbol ! ;
3283+ lateBindMemberContainer ( type ) ;
3284+ return type . symbol ! ;
32403285 }
32413286 // fallthrough
32423287 default :
32433288 // get the symbol from the node aliased type's node, or just return the base
32443289 // if it doesn't have a symbol (which will likely result in an error later on)
3245- return getMergedSymbol ( aliasType . node ! . symbol ) ?? aliasSymbol ;
3290+ return getMergedSymbol ( type . node ! . symbol ) ?? sym ;
32463291 }
32473292 }
32483293
@@ -5116,7 +5161,7 @@ export function createChecker(program: Program, resolver: NameResolver): Checker
51165161 */
51175162 function checkAugmentDecorator ( node : AugmentDecoratorStatementNode ) {
51185163 // This will validate the target type is pointing to a valid ref.
5119- resolveTypeReferenceSym ( node . targetType , undefined ) ;
5164+ resolveTypeReferenceSym ( node . targetType , undefined , { resolveDeclarationOfTemplate : true } ) ;
51205165 const links = resolver . getNodeLinks ( node . targetType ) ;
51215166 if ( links . isTemplateInstantiation ) {
51225167 program . reportDiagnostic (
@@ -5588,6 +5633,14 @@ export function createChecker(program: Program, resolver: NameResolver): Checker
55885633 ) : Map < string , Operation > {
55895634 const ownMembers = new Map < string , Operation > ( ) ;
55905635
5636+ // Preregister each operation sym links instantiation to make sure there is no race condition when instantiating templated interface
5637+ for ( const opNode of node . operations ) {
5638+ const symbol = getSymbolForMember ( opNode ) ;
5639+ const links = symbol && getSymbolLinks ( symbol ) ;
5640+ if ( links ) {
5641+ links . instantiations = new TypeInstantiationMap ( ) ;
5642+ }
5643+ }
55915644 for ( const opNode of node . operations ) {
55925645 const opType = checkOperation ( opNode , mapper , interfaceType ) ;
55935646 if ( ownMembers . has ( opType . name ) ) {
@@ -6709,15 +6762,21 @@ interface SymbolResolutionOptions {
67096762 resolveDecorators : boolean ;
67106763
67116764 /**
6712- * Should the symbol resolution instantiate templates and do a late bind of symbols.
6713- * @default true
6765+ * When resolving a symbol should it resolve to the declaration or template instance for ambiguous cases
6766+ * ```tsp
6767+ * model Foo<T = string> {}
6768+ * ```
6769+ *
6770+ * Does `Foo` reference to the `Foo<T>` or `Foo<string>` instance. By default it is the instance. Only case looking for declaration are augment decorator target
6771+ *
6772+ * @default false
67146773 */
6715- checkTemplateTypes : boolean ;
6774+ resolveDeclarationOfTemplate : boolean ;
67166775}
67176776
67186777const defaultSymbolResolutionOptions : SymbolResolutionOptions = {
67196778 resolveDecorators : false ,
6720- checkTemplateTypes : true ,
6779+ resolveDeclarationOfTemplate : false ,
67216780} ;
67226781
67236782function printTypeReferenceNode (
0 commit comments