@@ -404,6 +404,9 @@ struct IRGenContext
404
404
// The IRType value to lower into for `ThisType`.
405
405
IRInst* thisType = nullptr ;
406
406
407
+ // The IR witness value to use for `ThisType`
408
+ IRInst* thisTypeWitness = nullptr ;
409
+
407
410
explicit IRGenContext (SharedIRGenContext* inShared, ASTBuilder* inAstBuilder)
408
411
: shared(inShared)
409
412
, astBuilder(inAstBuilder)
@@ -1416,6 +1419,12 @@ struct ValLoweringVisitor : ValVisitor<ValLoweringVisitor, LoweredValInfo, Lower
1416
1419
return LoweredValInfo::simple (irWitnessTable);
1417
1420
}
1418
1421
1422
+ LoweredValInfo visitThisTypeSubtypeWitness (ThisTypeSubtypeWitness* val)
1423
+ {
1424
+ SLANG_UNUSED (val);
1425
+ return LoweredValInfo::simple (context->thisTypeWitness );
1426
+ }
1427
+
1419
1428
LoweredValInfo visitConstantIntVal (ConstantIntVal* val)
1420
1429
{
1421
1430
// TODO: it is a bit messy here that the `ConstantIntVal` representation
@@ -2233,6 +2242,31 @@ DeclRef<D> createDefaultSpecializedDeclRef(IRGenContext* context, D* decl)
2233
2242
return declRef.as <D>();
2234
2243
}
2235
2244
2245
+ static Type* _findReplacementThisParamType (
2246
+ IRGenContext* context,
2247
+ DeclRef<Decl> parentDeclRef)
2248
+ {
2249
+ if ( auto extensionDeclRef = parentDeclRef.as <ExtensionDecl>() )
2250
+ {
2251
+ auto targetType = getTargetType (context->astBuilder , extensionDeclRef);
2252
+ if (auto targetDeclRefType = as<DeclRefType>(targetType))
2253
+ {
2254
+ if (auto replacementType = _findReplacementThisParamType (context, targetDeclRefType->declRef ))
2255
+ return replacementType;
2256
+ }
2257
+ return targetType;
2258
+ }
2259
+
2260
+ if (auto interfaceDeclRef = parentDeclRef.as <InterfaceDecl>())
2261
+ {
2262
+ auto thisType = context->astBuilder ->create <ThisType>();
2263
+ thisType->interfaceDeclRef = interfaceDeclRef;
2264
+ return thisType;
2265
+ }
2266
+
2267
+ return nullptr ;
2268
+ }
2269
+
2236
2270
// / Get the type of the `this` parameter introduced by `parentDeclRef`, or null.
2237
2271
// /
2238
2272
// / E.g., if `parentDeclRef` is a `struct` declaration, then this will
@@ -2247,20 +2281,13 @@ Type* getThisParamTypeForContainer(
2247
2281
IRGenContext* context,
2248
2282
DeclRef<Decl> parentDeclRef)
2249
2283
{
2250
- if (auto interfaceDeclRef = parentDeclRef.as <InterfaceDecl>())
2251
- {
2252
- auto thisType = context->astBuilder ->create <ThisType>();
2253
- thisType->interfaceDeclRef = interfaceDeclRef;
2254
- return thisType;
2255
- }
2256
- else if ( auto aggTypeDeclRef = parentDeclRef.as <AggTypeDecl>() )
2284
+ if (auto replacementType = _findReplacementThisParamType (context, parentDeclRef))
2285
+ return replacementType;
2286
+
2287
+ if ( auto aggTypeDeclRef = parentDeclRef.as <AggTypeDecl>() )
2257
2288
{
2258
2289
return DeclRefType::create (context->astBuilder , aggTypeDeclRef);
2259
2290
}
2260
- else if ( auto extensionDeclRef = parentDeclRef.as <ExtensionDecl>() )
2261
- {
2262
- return getTargetType (context->astBuilder , extensionDeclRef);
2263
- }
2264
2291
2265
2292
return nullptr ;
2266
2293
}
@@ -5692,6 +5719,7 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo>
5692
5719
subContextStorage.env = &subEnvStorage;
5693
5720
5694
5721
subContextStorage.thisType = outerContext->thisType ;
5722
+ subContextStorage.thisTypeWitness = outerContext->thisTypeWitness ;
5695
5723
}
5696
5724
5697
5725
IRBuilder* getBuilder () { return &subBuilderStorage; }
@@ -5962,6 +5990,9 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo>
5962
5990
auto thisType = getBuilder ()->getThisType (irInterface);
5963
5991
subContext->thisType = thisType;
5964
5992
5993
+ // TODO: Need to add an appropriate stand-in witness here.
5994
+ subContext->thisTypeWitness = nullptr ;
5995
+
5965
5996
// Lower associated types first, so they can be referred to when lowering functions.
5966
5997
for (auto assocTypeDecl : decl->getMembersOfType <AssocTypeDecl>())
5967
5998
{
@@ -6303,6 +6334,45 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo>
6303
6334
return irGeneric;
6304
6335
}
6305
6336
6337
+ IRGeneric* emitOuterInterfaceGeneric (
6338
+ IRGenContext* subContext,
6339
+ ContainerDecl* parentDecl,
6340
+ DeclRefType* interfaceType,
6341
+ Decl* leafDecl)
6342
+ {
6343
+ auto subBuilder = subContext->irBuilder ;
6344
+
6345
+ // Of course, a generic might itself be nested inside of other generics...
6346
+ emitOuterGenerics (subContext, parentDecl, leafDecl);
6347
+
6348
+ // We need to create an IR generic
6349
+
6350
+ auto irGeneric = subBuilder->emitGeneric ();
6351
+ subBuilder->setInsertInto (irGeneric);
6352
+
6353
+ auto irBlock = subBuilder->emitBlock ();
6354
+ subBuilder->setInsertInto (irBlock);
6355
+
6356
+ // The generic needs two parameters: one to represent the
6357
+ // `ThisType`, and one to represent a witness that the
6358
+ // `ThisType` conforms to the interface itself.
6359
+ //
6360
+ auto irThisTypeParam = subBuilder->emitParam (subBuilder->getTypeType ());
6361
+
6362
+ auto irInterfaceType = lowerType (context, interfaceType);
6363
+ auto irWitnessTableParam = subBuilder->emitParam (subBuilder->getWitnessTableType (irInterfaceType));
6364
+ subBuilder->addTypeConstraintDecoration (irThisTypeParam, irInterfaceType);
6365
+
6366
+ // Now we need to wire up the IR parameters
6367
+ // we created to be used as the `ThisType` in
6368
+ // the body of the code.
6369
+ //
6370
+ subContext->thisType = irThisTypeParam;
6371
+ subContext->thisTypeWitness = irWitnessTableParam;
6372
+
6373
+ return irGeneric;
6374
+ }
6375
+
6306
6376
// If the given `decl` is enclosed in any generic declarations, then
6307
6377
// emit IR-level generics to represent them.
6308
6378
// The `leafDecl` represents the inner-most declaration we are actually
@@ -6316,6 +6386,23 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo>
6316
6386
{
6317
6387
return emitOuterGeneric (subContext, genericAncestor, leafDecl);
6318
6388
}
6389
+
6390
+ // We introduce IR generics in one other case, where the input
6391
+ // code wasn't visibly using generics: when a concrete member
6392
+ // is defined on an interface type. In that case, the resulting
6393
+ // definition needs to be generic on a parameter to represent
6394
+ // the `ThisType` of the interface.
6395
+ //
6396
+ if (auto extensionAncestor = as<ExtensionDecl>(pp))
6397
+ {
6398
+ if (auto targetDeclRefType = as<DeclRefType>(extensionAncestor->targetType ))
6399
+ {
6400
+ if (auto interfaceDeclRef = targetDeclRefType->declRef .as <InterfaceDecl>())
6401
+ {
6402
+ return emitOuterInterfaceGeneric (subContext, extensionAncestor, targetDeclRefType, leafDecl);
6403
+ }
6404
+ }
6405
+ }
6319
6406
}
6320
6407
6321
6408
return nullptr ;
@@ -7112,6 +7199,20 @@ bool canDeclLowerToAGeneric(Decl* decl)
7112
7199
return false ;
7113
7200
}
7114
7201
7202
+ static bool isInterfaceRequirement (Decl* decl)
7203
+ {
7204
+ auto ancestor = decl->parentDecl ;
7205
+ for (; ancestor; ancestor = ancestor->parentDecl )
7206
+ {
7207
+ if (as<InterfaceDecl>(ancestor))
7208
+ return true ;
7209
+
7210
+ if (as<ExtensionDecl>(ancestor))
7211
+ return false ;
7212
+ }
7213
+ return false ;
7214
+ }
7215
+
7115
7216
LoweredValInfo emitDeclRef (
7116
7217
IRGenContext* context,
7117
7218
Decl* decl,
@@ -7204,36 +7305,66 @@ LoweredValInfo emitDeclRef(
7204
7305
return lowerType (context, thisTypeSubst->witness ->sub );
7205
7306
}
7206
7307
7207
- // Somebody is trying to look up an interface requirement
7208
- // "through" some concrete type. We need to lower this decl-ref
7209
- // as a lookup of the corresponding member in a witness table.
7210
- //
7211
- // The witness table itself is referenced by the this-type
7212
- // substitution, so we can just lower that.
7213
- //
7214
- // Note: unlike the case for generics above, in the interface-lookup
7215
- // case, we don't end up caring about any further outer substitutions.
7216
- // That is because even if we are naming `ISomething<Foo>.doIt()`,
7217
- // a method inside a generic interface, we don't actually care
7218
- // about the substitution of `Foo` for the parameter `T` of
7219
- // `ISomething<T>`. That is because we really care about the
7220
- // witness table for the concrete type that conforms to `ISomething<Foo>`.
7221
- //
7222
- auto irWitnessTable = lowerSimpleVal (context, thisTypeSubst->witness );
7223
- //
7224
- // The key to use for looking up the interface member is
7225
- // derived from the declaration.
7226
- //
7227
- auto irRequirementKey = getInterfaceRequirementKey (context, decl);
7228
- //
7229
- // Those two pieces of information tell us what we need to
7230
- // do in order to look up the value that satisfied the requirement.
7231
- //
7232
- auto irSatisfyingVal = context->irBuilder ->emitLookupInterfaceMethodInst (
7233
- type,
7234
- irWitnessTable,
7235
- irRequirementKey);
7236
- return LoweredValInfo::simple (irSatisfyingVal);
7308
+ if (isInterfaceRequirement (decl))
7309
+ {
7310
+ // Somebody is trying to look up an interface requirement
7311
+ // "through" some concrete type. We need to lower this decl-ref
7312
+ // as a lookup of the corresponding member in a witness table.
7313
+ //
7314
+ // The witness table itself is referenced by the this-type
7315
+ // substitution, so we can just lower that.
7316
+ //
7317
+ // Note: unlike the case for generics above, in the interface-lookup
7318
+ // case, we don't end up caring about any further outer substitutions.
7319
+ // That is because even if we are naming `ISomething<Foo>.doIt()`,
7320
+ // a method inside a generic interface, we don't actually care
7321
+ // about the substitution of `Foo` for the parameter `T` of
7322
+ // `ISomething<T>`. That is because we really care about the
7323
+ // witness table for the concrete type that conforms to `ISomething<Foo>`.
7324
+ //
7325
+ auto irWitnessTable = lowerSimpleVal (context, thisTypeSubst->witness );
7326
+ //
7327
+ // The key to use for looking up the interface member is
7328
+ // derived from the declaration.
7329
+ //
7330
+ auto irRequirementKey = getInterfaceRequirementKey (context, decl);
7331
+ //
7332
+ // Those two pieces of information tell us what we need to
7333
+ // do in order to look up the value that satisfied the requirement.
7334
+ //
7335
+ auto irSatisfyingVal = context->irBuilder ->emitLookupInterfaceMethodInst (
7336
+ type,
7337
+ irWitnessTable,
7338
+ irRequirementKey);
7339
+ return LoweredValInfo::simple (irSatisfyingVal);
7340
+ }
7341
+ else
7342
+ {
7343
+ // This case is a reference to a member declaration of the interface
7344
+ // (or added by an extension of the interface) that does *not*
7345
+ // represent a requirement of the interface.
7346
+ //
7347
+ // Our policy is that concrete methods/members on an interface type
7348
+ // are lowered as generics, where the generic parameter represents
7349
+ // the `ThisType`.
7350
+ //
7351
+ auto genericVal = emitDeclRef (context, decl, thisTypeSubst->outer , context->irBuilder ->getGenericKind ());
7352
+ auto irGenericVal = getSimpleVal (context, genericVal);
7353
+
7354
+ // In order to reference the member for a particular type, we
7355
+ // specialize the generic for that type.
7356
+ //
7357
+ IRInst* irSubType = lowerType (context, thisTypeSubst->witness ->sub );
7358
+ IRInst* irSubTypeWitness = lowerSimpleVal (context, thisTypeSubst->witness );
7359
+
7360
+ IRInst* irSpecializeArgs[] = { irSubType, irSubTypeWitness };
7361
+ auto irSpecializedVal = context->irBuilder ->emitSpecializeInst (
7362
+ type,
7363
+ irGenericVal,
7364
+ 2 ,
7365
+ irSpecializeArgs);
7366
+ return LoweredValInfo::simple (irSpecializedVal);
7367
+ }
7237
7368
}
7238
7369
else
7239
7370
{
0 commit comments