diff options
Diffstat (limited to 'source')
| -rw-r--r-- | source/slang/check.cpp | 385 |
1 files changed, 199 insertions, 186 deletions
diff --git a/source/slang/check.cpp b/source/slang/check.cpp index 7c60d3cf2..04c41c4b0 100644 --- a/source/slang/check.cpp +++ b/source/slang/check.cpp @@ -3221,221 +3221,230 @@ namespace Slang if (decl->IsChecked(getCheckedState())) return; - // Look at inheritance clauses, and - // see if one of them is making the enum - // "inherit" from a concrete type. - // This will become the "tag" type - // of the enum. - RefPtr<Type> tagType; - InheritanceDecl* tagTypeInheritanceDecl = nullptr; - for(auto inheritanceDecl : decl->getMembersOfType<InheritanceDecl>()) + // We need to be careful to avoid recursion in the + // type-checking logic. We will do the minimal work + // to make the type usable in the first phase, and + // then check the actual cases in the second phase. + // + if(this->checkingPhase == CheckingPhase::Header) { - checkDecl(inheritanceDecl); + // Look at inheritance clauses, and + // see if one of them is making the enum + // "inherit" from a concrete type. + // This will become the "tag" type + // of the enum. + RefPtr<Type> tagType; + InheritanceDecl* tagTypeInheritanceDecl = nullptr; + for(auto inheritanceDecl : decl->getMembersOfType<InheritanceDecl>()) + { + checkDecl(inheritanceDecl); - // Look at the type being inherited from. - auto superType = inheritanceDecl->base.type; + // Look at the type being inherited from. + auto superType = inheritanceDecl->base.type; - if(auto errorType = superType->As<ErrorType>()) - { - // Ignore any erroneous inheritance clauses. - continue; - } - else if(auto declRefType = superType->As<DeclRefType>()) - { - if(auto interfaceDeclRef = declRefType->declRef.As<InterfaceDecl>()) + if(auto errorType = superType->As<ErrorType>()) { - // Don't consider interface bases as candidates for - // the tag type. + // Ignore any erroneous inheritance clauses. continue; } + else if(auto declRefType = superType->As<DeclRefType>()) + { + if(auto interfaceDeclRef = declRefType->declRef.As<InterfaceDecl>()) + { + // Don't consider interface bases as candidates for + // the tag type. + continue; + } + } + + if(tagType) + { + // We already found a tag type. + getSink()->diagnose(inheritanceDecl, Diagnostics::enumTypeAlreadyHasTagType); + getSink()->diagnose(tagTypeInheritanceDecl, Diagnostics::seePreviousTagType); + break; + } + else + { + tagType = superType; + tagTypeInheritanceDecl = inheritanceDecl; + } } - if(tagType) + // If a tag type has not been set, then we + // default it to the built-in `int` type. + // + // TODO: In the far-flung future we may want to distinguish + // `enum` types that have a "raw representation" like this from + // ones that are purely abstract and don't expose their + // type of their tag. + if(!tagType) { - // We already found a tag type. - getSink()->diagnose(inheritanceDecl, Diagnostics::enumTypeAlreadyHasTagType); - getSink()->diagnose(tagTypeInheritanceDecl, Diagnostics::seePreviousTagType); - break; + tagType = getSession()->getIntType(); } else { - tagType = superType; - tagTypeInheritanceDecl = inheritanceDecl; + // TODO: Need to establish that the tag + // type is suitable. (e.g., if we are going + // to allow raw values for case tags to be + // derived automatically, then the tag + // type needs to be some kind of interer type...) + // + // For now we will just be harsh and require it + // to be one of a few builtin types. + validateEnumTagType(tagType, tagTypeInheritanceDecl->loc); } - } - - // If a tag type has not been set, then we - // default it to the built-in `int` type. - // - // TODO: In the far-flung future we may want to distinguish - // `enum` types that have a "raw representation" like this from - // ones that are purely abstract and don't expose their - // type of their tag. - if(!tagType) - { - tagType = getSession()->getIntType(); - } - else - { - // TODO: Need to establish that the tag - // type is suitable. (e.g., if we are going - // to allow raw values for case tags to be - // derived automatically, then the tag - // type needs to be some kind of interer type...) - // - // For now we will just be harsh and require it - // to be one of a few builtin types. - validateEnumTagType(tagType, tagTypeInheritanceDecl->loc); - } - decl->tagType = tagType; + decl->tagType = tagType; - // An `enum` type should automatically conform to the `__EnumType` interface. - // The compiler needs to insert this conformance behind the scenes, and this - // seems like the best place to do it. - { - // First, look up the type of the `__EnumType` interface. - RefPtr<Type> enumTypeType = getSession()->getEnumTypeType(); + // An `enum` type should automatically conform to the `__EnumType` interface. + // The compiler needs to insert this conformance behind the scenes, and this + // seems like the best place to do it. + { + // First, look up the type of the `__EnumType` interface. + RefPtr<Type> enumTypeType = getSession()->getEnumTypeType(); - RefPtr<InheritanceDecl> enumConformanceDecl = new InheritanceDecl(); - enumConformanceDecl->ParentDecl = decl; - enumConformanceDecl->loc = decl->loc; - enumConformanceDecl->base.type = getSession()->getEnumTypeType(); - decl->Members.Add(enumConformanceDecl); + RefPtr<InheritanceDecl> enumConformanceDecl = new InheritanceDecl(); + enumConformanceDecl->ParentDecl = decl; + enumConformanceDecl->loc = decl->loc; + enumConformanceDecl->base.type = getSession()->getEnumTypeType(); + decl->Members.Add(enumConformanceDecl); - // The `__EnumType` interface has one required member, the `__Tag` type. - // We need to satisfy this requirement automatically, rather than require - // the user to actually declare a member with this name (otherwise we wouldn't - // let them define a tag value with the name `__Tag`). - // - RefPtr<WitnessTable> witnessTable = new WitnessTable(); - enumConformanceDecl->witnessTable = witnessTable; + // The `__EnumType` interface has one required member, the `__Tag` type. + // We need to satisfy this requirement automatically, rather than require + // the user to actually declare a member with this name (otherwise we wouldn't + // let them define a tag value with the name `__Tag`). + // + RefPtr<WitnessTable> witnessTable = new WitnessTable(); + enumConformanceDecl->witnessTable = witnessTable; - Name* tagAssociatedTypeName = getSession()->getNameObj("__Tag"); - Decl* tagAssociatedTypeDecl = nullptr; - if(auto enumTypeTypeDeclRefType = enumTypeType.As<DeclRefType>()) - { - if(auto enumTypeTypeInterfaceDecl = enumTypeTypeDeclRefType->declRef.getDecl()->As<InterfaceDecl>()) + Name* tagAssociatedTypeName = getSession()->getNameObj("__Tag"); + Decl* tagAssociatedTypeDecl = nullptr; + if(auto enumTypeTypeDeclRefType = enumTypeType.As<DeclRefType>()) { - for(auto memberDecl : enumTypeTypeInterfaceDecl->Members) + if(auto enumTypeTypeInterfaceDecl = enumTypeTypeDeclRefType->declRef.getDecl()->As<InterfaceDecl>()) { - if(memberDecl->getName() == tagAssociatedTypeName) + for(auto memberDecl : enumTypeTypeInterfaceDecl->Members) { - tagAssociatedTypeDecl = memberDecl; - break; + if(memberDecl->getName() == tagAssociatedTypeName) + { + tagAssociatedTypeDecl = memberDecl; + break; + } } } } - } - if(!tagAssociatedTypeDecl) - { - SLANG_DIAGNOSE_UNEXPECTED(getSink(), decl, "failed to find built-in declaration '__Tag'"); - } + if(!tagAssociatedTypeDecl) + { + SLANG_DIAGNOSE_UNEXPECTED(getSink(), decl, "failed to find built-in declaration '__Tag'"); + } - // Okay, add the conformance withess for `__Tag` being satisfied by `tagType` - witnessTable->requirementDictionary.Add(tagAssociatedTypeDecl, RequirementWitness(tagType)); + // Okay, add the conformance withess for `__Tag` being satisfied by `tagType` + witnessTable->requirementDictionary.Add(tagAssociatedTypeDecl, RequirementWitness(tagType)); - // TODO: we actually also need to synthesize a witness for the conformance of `tagType` - // to the `__BuiltinIntegerType` interface, because that is a constraint on the - // associated type `__Tag`. + // TODO: we actually also need to synthesize a witness for the conformance of `tagType` + // to the `__BuiltinIntegerType` interface, because that is a constraint on the + // associated type `__Tag`. - // TODO: eventually we should consider synthesizing other requirements for - // the min/max tag values, or the total number of tags, so that people don't - // have to declare these as additional cases. + // TODO: eventually we should consider synthesizing other requirements for + // the min/max tag values, or the total number of tags, so that people don't + // have to declare these as additional cases. - enumConformanceDecl->SetCheckState(DeclCheckState::Checked); + enumConformanceDecl->SetCheckState(DeclCheckState::Checked); + } } - - - decl->SetCheckState(DeclCheckState::CheckedHeader); - - auto enumType = DeclRefType::Create( - getSession(), - makeDeclRef(decl)); - - // Check the enum cases in order. - for(auto caseDecl : decl->getMembersOfType<EnumCaseDecl>()) + else if( checkingPhase == CheckingPhase::Body ) { - // Each case defines a value of the enum's type. - // - // TODO: If we ever support enum cases with payloads, - // then they would probably have a type that is a - // `FunctionType` from the payload types to the - // enum type. - // - caseDecl->type.type = enumType; + auto enumType = DeclRefType::Create( + getSession(), + makeDeclRef(decl)); - checkDecl(caseDecl); - } + auto tagType = decl->tagType; - // For any enum case that didn't provide an explicit - // tag value, derived an appropriate tag value. - IntegerLiteralValue defaultTag = 0; - for(auto caseDecl : decl->getMembersOfType<EnumCaseDecl>()) - { - if(auto explicitTagValExpr = caseDecl->initExpr) + // Check the enum cases in order. + for(auto caseDecl : decl->getMembersOfType<EnumCaseDecl>()) { - // This tag has an initializer, so it should establish - // the tag value for a successor case that doesn't - // provide an explicit tag. + // Each case defines a value of the enum's type. + // + // TODO: If we ever support enum cases with payloads, + // then they would probably have a type that is a + // `FunctionType` from the payload types to the + // enum type. + // + caseDecl->type.type = enumType; - RefPtr<IntVal> explicitTagVal = TryConstantFoldExpr(explicitTagValExpr); - if(explicitTagVal) + checkDecl(caseDecl); + } + + // For any enum case that didn't provide an explicit + // tag value, derived an appropriate tag value. + IntegerLiteralValue defaultTag = 0; + for(auto caseDecl : decl->getMembersOfType<EnumCaseDecl>()) + { + if(auto explicitTagValExpr = caseDecl->initExpr) { - if(auto constIntVal = explicitTagVal.As<ConstantIntVal>()) + // This tag has an initializer, so it should establish + // the tag value for a successor case that doesn't + // provide an explicit tag. + + RefPtr<IntVal> explicitTagVal = TryConstantFoldExpr(explicitTagValExpr); + if(explicitTagVal) { - defaultTag = constIntVal->value; + if(auto constIntVal = explicitTagVal.As<ConstantIntVal>()) + { + defaultTag = constIntVal->value; + } + else + { + // TODO: need to handle other possibilities here + getSink()->diagnose(explicitTagValExpr, Diagnostics::unexpectedEnumTagExpr); + } } else { - // TODO: need to handle other possibilities here - getSink()->diagnose(explicitTagValExpr, Diagnostics::unexpectedEnumTagExpr); + // If this happens, then the explicit tag value expression + // doesn't seem to be a constant after all. In this case + // we expect the checking logic to have applied already. } } else { - // If this happens, then the explicit tag value expression - // doesn't seem to be a constant after all. In this case - // we expect the checking logic to have applied already. + // This tag has no initializer, so it should use + // the default tag value we are tracking. + RefPtr<IntegerLiteralExpr> tagValExpr = new IntegerLiteralExpr(); + tagValExpr->loc = caseDecl->loc; + tagValExpr->type = QualType(tagType); + tagValExpr->value = defaultTag; + + caseDecl->initExpr = tagValExpr; } - } - else - { - // This tag has no initializer, so it should use - // the default tag value we are tracking. - RefPtr<IntegerLiteralExpr> tagValExpr = new IntegerLiteralExpr(); - tagValExpr->loc = caseDecl->loc; - tagValExpr->type = QualType(tagType); - tagValExpr->value = defaultTag; - caseDecl->initExpr = tagValExpr; + // Default tag for the next case will be one more than + // for the most recent case. + // + // TODO: We might consider adding a `[flags]` attribute + // that modifies this behavior to be `defaultTagForCase <<= 1`. + // + defaultTag++; } - // Default tag for the next case will be one more than - // for the most recent case. - // - // TODO: We might consider adding a `[flags]` attribute - // that modifies this behavior to be `defaultTagForCase <<= 1`. - // - defaultTag++; - } - - // Now check any other member declarations. - for(auto memberDecl : decl->Members) - { - // Already checked inheritance declarations above. - if(auto inheritanceDecl = memberDecl->As<InheritanceDecl>()) - continue; + // Now check any other member declarations. + for(auto memberDecl : decl->Members) + { + // Already checked inheritance declarations above. + if(auto inheritanceDecl = memberDecl->As<InheritanceDecl>()) + continue; - // Already checked enum case declarations above. - if(auto caseDecl = memberDecl->As<EnumCaseDecl>()) - continue; + // Already checked enum case declarations above. + if(auto caseDecl = memberDecl->As<EnumCaseDecl>()) + continue; - // TODO: Right now we don't support other kinds of - // member declarations on an `enum`, but that is - // something we may want to allow in the long run. - // - checkDecl(memberDecl); + // TODO: Right now we don't support other kinds of + // member declarations on an `enum`, but that is + // something we may want to allow in the long run. + // + checkDecl(memberDecl); + } } decl->SetCheckState(getCheckedState()); } @@ -3445,31 +3454,35 @@ namespace Slang if (decl->IsChecked(getCheckedState())) return; - // An enum case had better appear inside an enum! - // - // TODO: Do we need/want to support generic cases some day? - auto parentEnumDecl = decl->ParentDecl->As<EnumDecl>(); - SLANG_ASSERT(parentEnumDecl); + if(checkingPhase == CheckingPhase::Body) + { + // An enum case had better appear inside an enum! + // + // TODO: Do we need/want to support generic cases some day? + auto parentEnumDecl = decl->ParentDecl->As<EnumDecl>(); + SLANG_ASSERT(parentEnumDecl); - // The tag type should have already been set by - // the surrounding `enum` declaration. - auto tagType = parentEnumDecl->tagType; - SLANG_ASSERT(tagType); + // The tag type should have already been set by + // the surrounding `enum` declaration. + auto tagType = parentEnumDecl->tagType; + SLANG_ASSERT(tagType); - // Need to check the init expression, if present, since - // that represents the explicit tag for this case. - if(auto initExpr = decl->initExpr) - { - initExpr = CheckExpr(initExpr); - initExpr = Coerce(tagType, initExpr); + // Need to check the init expression, if present, since + // that represents the explicit tag for this case. + if(auto initExpr = decl->initExpr) + { + initExpr = CheckExpr(initExpr); + initExpr = Coerce(tagType, initExpr); - // We want to enforce that this is an integer constant - // expression, but we don't actually care to retain - // the value. - CheckIntegerConstantExpression(initExpr); + // We want to enforce that this is an integer constant + // expression, but we don't actually care to retain + // the value. + CheckIntegerConstantExpression(initExpr); - decl->initExpr = initExpr; + decl->initExpr = initExpr; + } } + decl->SetCheckState(getCheckedState()); } |
