diff options
| author | Yong He <yonghe@outlook.com> | 2022-07-12 22:45:05 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-07-12 22:45:05 -0700 |
| commit | 049aac1b80143753b4b3449e529024bafe2250be (patch) | |
| tree | e6734ef240bf7016562a301009add1761caf06f6 /source | |
| parent | a6775666c38ccaeb2a991921a08343afa09c659b (diff) | |
Support `class` types. (#2321)
* Support `class` types.
* Ignore class-keyword test
* Fix codereview comments and warnings.
Co-authored-by: Yong He <yhe@nvidia.com>
Diffstat (limited to 'source')
| -rw-r--r-- | source/slang/slang-ast-expr.h | 5 | ||||
| -rw-r--r-- | source/slang/slang-check-decl.cpp | 78 | ||||
| -rw-r--r-- | source/slang/slang-check-expr.cpp | 2 | ||||
| -rw-r--r-- | source/slang/slang-check-impl.h | 4 | ||||
| -rw-r--r-- | source/slang/slang-check-overload.cpp | 37 | ||||
| -rw-r--r-- | source/slang/slang-diagnostic-defs.h | 13 | ||||
| -rw-r--r-- | source/slang/slang-emit-c-like.cpp | 61 | ||||
| -rw-r--r-- | source/slang/slang-emit-c-like.h | 2 | ||||
| -rw-r--r-- | source/slang/slang-emit-cpp.cpp | 7 | ||||
| -rw-r--r-- | source/slang/slang-ir-inst-defs.h | 2 | ||||
| -rw-r--r-- | source/slang/slang-ir-insts.h | 7 | ||||
| -rw-r--r-- | source/slang/slang-ir-util.cpp | 29 | ||||
| -rw-r--r-- | source/slang/slang-ir-util.h | 22 | ||||
| -rw-r--r-- | source/slang/slang-ir.cpp | 33 | ||||
| -rw-r--r-- | source/slang/slang-ir.h | 13 | ||||
| -rw-r--r-- | source/slang/slang-lower-to-ir.cpp | 59 | ||||
| -rw-r--r-- | source/slang/slang-parser.cpp | 58 |
17 files changed, 360 insertions, 72 deletions
diff --git a/source/slang/slang-ast-expr.h b/source/slang/slang-ast-expr.h index 7226f365e..3fbbe05ea 100644 --- a/source/slang/slang-ast-expr.h +++ b/source/slang/slang-ast-expr.h @@ -181,6 +181,11 @@ class TryExpr : public Expr Scope* scope = nullptr; }; +class NewExpr : public InvokeExpr +{ + SLANG_AST_CLASS(NewExpr) +}; + class OperatorExpr: public InvokeExpr { SLANG_AST_CLASS(OperatorExpr) diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index 94858b679..22567c889 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -90,6 +90,8 @@ namespace Slang void visitStructDecl(StructDecl* decl); + void visitClassDecl(ClassDecl* decl); + /// Get the type of the storage accessed by an accessor. /// /// The type of storage is determined by the parent declaration. @@ -149,6 +151,8 @@ namespace Slang void visitStructDecl(StructDecl* decl); + void visitClassDecl(ClassDecl* decl); + void visitEnumDecl(EnumDecl* decl); /// Validate that the target type of an extension `decl` is valid. @@ -1065,6 +1069,11 @@ namespace Slang } } + void SemanticsDeclHeaderVisitor::visitClassDecl(ClassDecl* classDecl) + { + SLANG_UNUSED(classDecl); + } + void SemanticsDeclBodyVisitor::checkVarDeclCommon(VarDeclBase* varDecl) { if (auto initExpr = varDecl->initExpr) @@ -3370,6 +3379,75 @@ namespace Slang } } + void SemanticsDeclBasesVisitor::visitClassDecl(ClassDecl* decl) + { + // A `class` type can only inherit from `class` or `interface` types. + // + // Furthermore, only the first inheritance clause (in source + // order) is allowed to declare a base `class` type. + // + Index inheritanceClauseCounter = 0; + for (auto inheritanceDecl : decl->getMembersOfType<InheritanceDecl>()) + { + Index inheritanceClauseIndex = inheritanceClauseCounter++; + + ensureDecl(inheritanceDecl, DeclCheckState::CanUseBaseOfInheritanceDecl); + auto baseType = inheritanceDecl->base.type; + + // It is possible that there was an error in checking the base type + // expression, and in such a case we shouldn't emit a cascading error. + // + if (auto baseErrorType = as<ErrorType>(baseType)) + { + continue; + } + + auto baseDeclRefType = as<DeclRefType>(baseType); + if (!baseDeclRefType) + { + getSink()->diagnose(inheritanceDecl, Diagnostics::baseOfClassMustBeClassOrInterface, decl, baseType); + continue; + } + + auto baseDeclRef = baseDeclRefType->declRef; + if (auto baseInterfaceDeclRef = baseDeclRef.as<InterfaceDecl>()) + { + } + else if (auto baseStructDeclRef = baseDeclRef.as<ClassDecl>()) + { + // To simplify the task of reading and maintaining code, + // we require that when a `class` inherits from another + // `class`, the base `class` is the first item in + // the list of bases (before any interfaces). + // + // This constraint also has the secondary effect of restricting + // it so that a `struct` cannot multiply inherit from other + // `struct` types. + // + if (inheritanceClauseIndex != 0) + { + getSink()->diagnose(inheritanceDecl, Diagnostics::baseClassMustBeListedFirst, decl, baseType); + } + } + else + { + getSink()->diagnose(inheritanceDecl, Diagnostics::baseOfClassMustBeClassOrInterface, decl, baseType); + continue; + } + + // TODO: At this point we have the `baseDeclRef` + // and could use it to perform further validity checks, + // and/or to build up a more refined representation of + // the inheritance graph for this type (e.g., a "class + // precedence list"). + // + // E.g., we can/should check that we aren't introducing + // a circular inheritance relationship. + + _validateCrossModuleInheritance(decl, inheritanceDecl); + } + } + bool SemanticsVisitor::isIntegerBaseType(BaseType baseType) { return (BaseTypeInfo::getInfo(baseType).flags & BaseTypeInfo::Flag::Integer) != 0; diff --git a/source/slang/slang-check-expr.cpp b/source/slang/slang-check-expr.cpp index a3fec4802..03da084d3 100644 --- a/source/slang/slang-check-expr.cpp +++ b/source/slang/slang-check-expr.cpp @@ -1675,7 +1675,7 @@ namespace Slang Expr* SemanticsExprVisitor::visitTryExpr(TryExpr* expr) { - auto prevTryClauseType = expr->tryClauseType; + auto prevTryClauseType = m_enclosingTryClauseType; m_enclosingTryClauseType = expr->tryClauseType; expr->base = CheckTerm(expr->base); m_enclosingTryClauseType = prevTryClauseType; diff --git a/source/slang/slang-check-impl.h b/source/slang/slang-check-impl.h index ccf9ccad3..ce1093d09 100644 --- a/source/slang/slang-check-impl.h +++ b/source/slang/slang-check-impl.h @@ -1387,6 +1387,10 @@ namespace Slang // count the number of parameters required/allowed for a generic ParamCounts CountParameters(DeclRef<GenericDecl> genericRef); + bool TryCheckOverloadCandidateClassNewMatchUp( + OverloadResolveContext& context, + OverloadCandidate const& candidate); + bool TryCheckOverloadCandidateArity( OverloadResolveContext& context, OverloadCandidate const& candidate); diff --git a/source/slang/slang-check-overload.cpp b/source/slang/slang-check-overload.cpp index bd27c7df2..be351a78f 100644 --- a/source/slang/slang-check-overload.cpp +++ b/source/slang/slang-check-overload.cpp @@ -60,6 +60,40 @@ namespace Slang return counts; } + bool SemanticsVisitor::TryCheckOverloadCandidateClassNewMatchUp(OverloadResolveContext& context, OverloadCandidate const& candidate) + { + // Check that a constructor call to a class type must be in a `new` expr, and a `new` expr + // is only used to construct a class. + bool isClassType = false; + bool isNewExpr = false; + if (auto ctorDeclRef = candidate.item.declRef.as<ConstructorDecl>()) + { + if (auto resultType = as<DeclRefType>(candidate.resultType)) + { + if (resultType->declRef.as<ClassDecl>()) + { + isClassType = true; + } + } + } + if (as<NewExpr>(context.originalExpr)) + { + isNewExpr = true; + } + + if (isNewExpr && !isClassType) + { + getSink()->diagnose(context.originalExpr, Diagnostics::newCanOnlyBeUsedToInitializeAClass); + return false; + } + if (!isNewExpr && isClassType) + { + getSink()->diagnose(context.originalExpr, Diagnostics::classCanOnlyBeInitializedWithNew); + return false; + } + return true; + } + bool SemanticsVisitor::TryCheckOverloadCandidateArity( OverloadResolveContext& context, OverloadCandidate const& candidate) @@ -572,6 +606,9 @@ namespace Slang context.mode = OverloadResolveContext::Mode::ForReal; + if (!TryCheckOverloadCandidateClassNewMatchUp(context, candidate)) + goto error; + if (!TryCheckOverloadCandidateArity(context, candidate)) goto error; diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h index ff2775328..85f5f5fb0 100644 --- a/source/slang/slang-diagnostic-defs.h +++ b/source/slang/slang-diagnostic-defs.h @@ -277,6 +277,9 @@ DIAGNOSTIC(30043, Error, getStringHashRequiresStringLiteral, "getStringHash para DIAGNOSTIC(30060, Error, expectedAType, "expected a type, got a '$0'") DIAGNOSTIC(30061, Error, expectedANamespace, "expected a namespace, got a '$0'") +DIAGNOSTIC(30065, Error, newCanOnlyBeUsedToInitializeAClass, "`new` can only be used to initialize a class") +DIAGNOSTIC(30066, Error, classCanOnlyBeInitializedWithNew, "a class can only be initialized by a `new` clause") + DIAGNOSTIC(30100, Error, staticRefToNonStaticMember, "type '$0' cannot be used to refer to non-static member '$1'") DIAGNOSTIC(30200, Error, redeclaration, "declaration of '$0' conflicts with existing declaration") @@ -357,14 +360,16 @@ DIAGNOSTIC(30700, Error, outputParameterCannotHaveDefaultValue, "an 'out' or 'in DIAGNOSTIC(30810, Error, baseOfInterfaceMustBeInterface, "interface '$0' cannot inherit from non-interface type '$1'") DIAGNOSTIC(30811, Error, baseOfStructMustBeStructOrInterface, "struct '$0' cannot inherit from type '$1' that is neither a struct nor an interface") DIAGNOSTIC(30812, Error, baseOfEnumMustBeIntegerOrInterface, "enum '$0' cannot inherit from type '$1' that is neither an interface not a builtin integer type") -DIAGNOSTIC(30810, Error, baseOfExtensionMustBeInterface, "extension cannot inherit from non-interface type '$1'") +DIAGNOSTIC(30813, Error, baseOfExtensionMustBeInterface, "extension cannot inherit from non-interface type '$1'") +DIAGNOSTIC(30814, Error, baseOfClassMustBeClassOrInterface, "class '$0' cannot inherit from type '$1' that is neither a class nor an interface") DIAGNOSTIC(30820, Error, baseStructMustBeListedFirst, "a struct type may only inherit from one other struct type, and that type must appear first in the list of bases") DIAGNOSTIC(30821, Error, tagTypeMustBeListedFirst, "an unum type may only have a single tag type, and that type must be listed first in the list of bases") +DIAGNOSTIC(30822, Error, baseClassMustBeListedFirst, "a class type may only inherit from one other class type, and that type must appear first in the list of bases") -DIAGNOSTIC(30820, Error, cannotInheritFromExplicitlySealedDeclarationInAnotherModule, "cannot inherit from type '$0' marked 'sealed' in module '$1'") -DIAGNOSTIC(30821, Error, cannotInheritFromImplicitlySealedDeclarationInAnotherModule, "cannot inherit from type '$0' in module '$1' because it is implicitly 'sealed'; mark the base type 'open' to allow inheritance across modules") -DIAGNOSTIC(30822, Error, invalidTypeForInheritance, "type '$0' cannot be used for inheritance") +DIAGNOSTIC(30830, Error, cannotInheritFromExplicitlySealedDeclarationInAnotherModule, "cannot inherit from type '$0' marked 'sealed' in module '$1'") +DIAGNOSTIC(30831, Error, cannotInheritFromImplicitlySealedDeclarationInAnotherModule, "cannot inherit from type '$0' in module '$1' because it is implicitly 'sealed'; mark the base type 'open' to allow inheritance across modules") +DIAGNOSTIC(30832, Error, invalidTypeForInheritance, "type '$0' cannot be used for inheritance") DIAGNOSTIC(30850, Error, invalidExtensionOnType, "type '$0' cannot be extended. `extension` can only be used to extend a nominal type.") diff --git a/source/slang/slang-emit-c-like.cpp b/source/slang/slang-emit-c-like.cpp index 9bd999087..1e0eb614d 100644 --- a/source/slang/slang-emit-c-like.cpp +++ b/source/slang/slang-emit-c-like.cpp @@ -15,6 +15,7 @@ #include "slang-ir-specialize-resources.h" #include "slang-ir-ssa.h" #include "slang-ir-union.h" +#include "slang-ir-util.h" #include "slang-ir-validate.h" #include "slang-legalize-types.h" #include "slang-lower-to-ir.h" @@ -28,7 +29,6 @@ #include "slang-emit-source-writer.h" #include "slang-mangled-lexer.h" - #include <assert.h> namespace Slang { @@ -1617,6 +1617,11 @@ void CLikeSourceEmitter::defaultEmitInstExpr(IRInst* inst, const EmitOpInfo& inO emitType(inst->getDataType()); emitArgs(inst); break; + case kIROp_AllocObj: + m_writer->emit("new "); + m_writer->emit(getName(inst->getDataType())); + m_writer->emit("()"); + break; case kIROp_makeUInt64: m_writer->emit("(("); emitType(inst->getDataType()); @@ -1649,7 +1654,10 @@ void CLikeSourceEmitter::defaultEmitInstExpr(IRInst* inst, const EmitOpInfo& inO auto base = fieldExtract->getBase(); emitOperand(base, leftSide(outerPrec, prec)); - m_writer->emit("."); + if (base->getDataType()->getOp() == kIROp_ClassType) + m_writer->emit("->"); + else + m_writer->emit("."); if(getSourceLanguage() == SourceLanguage::GLSL && as<IRUniformParameterGroupType>(base->getDataType())) { @@ -1673,7 +1681,10 @@ void CLikeSourceEmitter::defaultEmitInstExpr(IRInst* inst, const EmitOpInfo& inO auto innerPrec = getInfo(EmitOp::Postfix); bool innerNeedClose = maybeEmitParens(outerPrec, innerPrec); auto base = ii->getBase(); - emitOperand(base, leftSide(outerPrec, innerPrec)); + if (isPtrToClassType(base->getDataType())) + emitDereferenceOperand(base, leftSide(outerPrec, innerPrec)); + else + emitOperand(base, leftSide(outerPrec, innerPrec)); m_writer->emit("->"); m_writer->emit(getName(ii->getField())); maybeCloseParens(innerNeedClose); @@ -2771,6 +2782,46 @@ void CLikeSourceEmitter::emitStruct(IRStructType* structType) m_writer->emit("};\n\n"); } +void CLikeSourceEmitter::emitClass(IRClassType* classType) +{ + // If the selected `class` type is actually an intrinsic + // on our target, then we don't want to emit anything at all. + if (auto intrinsicDecoration = findBestTargetIntrinsicDecoration(classType)) + { + return; + } + + m_writer->emit("class "); + + emitPostKeywordTypeAttributes(classType); + + m_writer->emit(getName(classType)); + m_writer->emit(" : public RefObject"); + m_writer->emit("\n{\n"); + m_writer->emit("public:\n"); + m_writer->indent(); + + for (auto ff : classType->getFields()) + { + auto fieldKey = ff->getKey(); + auto fieldType = ff->getFieldType(); + + // Filter out fields with `void` type that might + // have been introduced by legalization. + if (as<IRVoidType>(fieldType)) + continue; + + emitInterpolationModifiers(fieldKey, fieldType, nullptr); + + emitType(fieldType, getName(fieldKey)); + emitSemantics(fieldKey); + m_writer->emit(";\n"); + } + + m_writer->dedent(); + m_writer->emit("};\n\n"); +} + void CLikeSourceEmitter::emitInterpolationModifiers(IRInst* varInst, IRType* valueType, IRVarLayout* layout) { emitInterpolationModifiersImpl(varInst, valueType, layout); @@ -3119,7 +3170,9 @@ void CLikeSourceEmitter::emitGlobalInstImpl(IRInst* inst) case kIROp_StructType: emitStruct(cast<IRStructType>(inst)); break; - + case kIROp_ClassType: + emitClass(cast<IRClassType>(inst)); + break; case kIROp_InterfaceType: emitInterface(cast<IRInterfaceType>(inst)); break; diff --git a/source/slang/slang-emit-c-like.h b/source/slang/slang-emit-c-like.h index ddda94e84..825223278 100644 --- a/source/slang/slang-emit-c-like.h +++ b/source/slang/slang-emit-c-like.h @@ -353,6 +353,8 @@ public: void emitFuncDecorations(IRFunc* func) { emitFuncDecorationsImpl(func); } void emitStruct(IRStructType* structType); + void emitClass(IRClassType* structType); + /// Emit type attributes that should appear after, e.g., a `struct` keyword diff --git a/source/slang/slang-emit-cpp.cpp b/source/slang/slang-emit-cpp.cpp index b52407412..96b42af43 100644 --- a/source/slang/slang-emit-cpp.cpp +++ b/source/slang/slang-emit-cpp.cpp @@ -560,6 +560,13 @@ SlangResult CPPSourceEmitter::calcTypeName(IRType* type, CodeGenTarget target, S out << ">"; return SLANG_OK; } + case kIROp_ClassType: + { + out << "RefPtr<"; + out << getName(type); + out << ">"; + return SLANG_OK; + } default: { if (isNominalOp(type->getOp())) diff --git a/source/slang/slang-ir-inst-defs.h b/source/slang/slang-ir-inst-defs.h index b4530d655..a91c21434 100644 --- a/source/slang/slang-ir-inst-defs.h +++ b/source/slang/slang-ir-inst-defs.h @@ -198,6 +198,7 @@ INST(Nop, nop, 0, 0) // `field` instructions. // INST(StructType, struct, 0, PARENT) +INST(ClassType, class, 0, PARENT) INST(InterfaceType, interface, 0, 0) INST(AssociatedType, associated_type, 0, 0) INST(ThisType, this_type, 0, 0) @@ -271,6 +272,7 @@ INST(lookup_witness_table, lookup_witness_table, 2, 0) INST(BindGlobalGenericParam, bind_global_generic_param, 2, 0) INST(Construct, construct, 0, 0) +INST(AllocObj, allocObj, 0, 0) INST(makeUInt64, makeUInt64, 2, 0) INST(makeVector, makeVector, 0, 0) diff --git a/source/slang/slang-ir-insts.h b/source/slang/slang-ir-insts.h index 7d0609645..b8cce4c17 100644 --- a/source/slang/slang-ir-insts.h +++ b/source/slang/slang-ir-insts.h @@ -2578,6 +2578,9 @@ public: // Create an initially empty `struct` type. IRStructType* createStructType(); + // Create an initially empty `class` type. + IRClassType* createClassType(); + // Create an empty `interface` type. IRInterfaceType* createInterfaceType(UInt operandCount, IRInst* const* operands); @@ -2587,7 +2590,7 @@ public: // Create a field nested in a struct type, declaring that // the specified field key maps to a field with the specified type. IRStructField* createStructField( - IRStructType* structType, + IRType* aggType, IRStructKey* fieldKey, IRType* fieldType); @@ -2637,6 +2640,8 @@ public: IRParam* emitParamAtHead( IRType* type); + IRInst* emitAllocObj(IRType* type); + IRVar* emitVar( IRType* type); diff --git a/source/slang/slang-ir-util.cpp b/source/slang/slang-ir-util.cpp new file mode 100644 index 000000000..fda7b25cc --- /dev/null +++ b/source/slang/slang-ir-util.cpp @@ -0,0 +1,29 @@ +#include "slang-ir-util.h" + +namespace Slang +{ + +bool isPointerOfType(IRInst* type, IROp opCode) +{ + if (auto ptrType = as<IRPtrTypeBase>(type)) + { + return ptrType->getValueType() && ptrType->getValueType()->getOp() == opCode; + } + return false; +} + +bool isPointerOfType(IRInst* type, IRInst* elementType) +{ + if (auto ptrType = as<IRPtrTypeBase>(type)) + { + return ptrType->getValueType() && isTypeEqual(ptrType->getValueType(), (IRType*)elementType); + } + return false; +} + +bool isPtrToClassType(IRInst* type) +{ + return isPointerOfType(type, kIROp_ClassType); +} + +} diff --git a/source/slang/slang-ir-util.h b/source/slang/slang-ir-util.h new file mode 100644 index 000000000..69a9c4d16 --- /dev/null +++ b/source/slang/slang-ir-util.h @@ -0,0 +1,22 @@ +// slang-ir-util.h +#ifndef SLANG_IR_UTIL_H_INCLUDED +#define SLANG_IR_UTIL_H_INCLUDED + +// This file contains utility functions for operating with Slang IR. +// +#include "slang-ir.h" + +namespace Slang +{ + +bool isPtrToClassType(IRInst* type); + +// True if ptrType is a pointer type to elementType +bool isPointerOfType(IRInst* ptrType, IRInst* elementType); + +// True if ptrType is a pointer type to a type of opCode +bool isPointerOfType(IRInst* ptrType, IROp opCode); + +} + +#endif diff --git a/source/slang/slang-ir.cpp b/source/slang/slang-ir.cpp index 081b9103f..ca6435d8e 100644 --- a/source/slang/slang-ir.cpp +++ b/source/slang/slang-ir.cpp @@ -3560,6 +3560,16 @@ namespace Slang return structType; } + IRClassType* IRBuilder::createClassType() + { + IRClassType* classType = createInst<IRClassType>( + this, + kIROp_ClassType, + getTypeKind()); + addGlobalValue(this, classType); + return classType; + } + IRInterfaceType* IRBuilder::createInterfaceType(UInt operandCount, IRInst* const* operands) { IRInterfaceType* interfaceType = createInst<IRInterfaceType>( @@ -3585,7 +3595,7 @@ namespace Slang // Create a field nested in a struct type, declaring that // the specified field key maps to a field with the specified type. IRStructField* IRBuilder::createStructField( - IRStructType* structType, + IRType* aggType, IRStructKey* fieldKey, IRType* fieldType) { @@ -3599,9 +3609,9 @@ namespace Slang 2, operands); - if (structType) + if (aggType) { - field->insertAtEnd(structType); + field->insertAtEnd(aggType); } return field; @@ -3696,6 +3706,11 @@ namespace Slang return param; } + IRInst* IRBuilder::emitAllocObj(IRType* type) + { + return emitIntrinsicInst(type, kIROp_AllocObj, 0, nullptr); + } + IRVar* IRBuilder::emitVar( IRType* type) { @@ -5527,6 +5542,7 @@ namespace Slang switch (op) { case kIROp_StructType: + case kIROp_ClassType: case kIROp_InterfaceType: case kIROp_Generic: case kIROp_Param: @@ -6081,6 +6097,7 @@ namespace Slang case kIROp_ExtractExistentialWitnessTable: case kIROp_WrapExistential: case kIROp_BitCast: + case kIROp_AllocObj: return false; } } @@ -6313,16 +6330,6 @@ namespace Slang irValue->getDataType())); } - bool isPointerOfType(IRInst* ptrType, IRInst* elementType) - { - return ptrType && ptrType->getOp() == kIROp_PtrType && ptrType->getOperand(0) == elementType; - } - - bool isPointerOfType(IRInst* ptrType, IROp opCode) - { - return ptrType && ptrType->getOp() == kIROp_PtrType && ptrType->getOperand(0) && - ptrType->getOperand(0)->getOp() == opCode; - } bool isBuiltin(IRInst* inst) { return inst->findDecoration<IRBuiltinDecoration>() != nullptr; diff --git a/source/slang/slang-ir.h b/source/slang/slang-ir.h index 0a27eb4cd..3faa5884c 100644 --- a/source/slang/slang-ir.h +++ b/source/slang/slang-ir.h @@ -1408,6 +1408,13 @@ struct IRStructType : IRType IR_LEAF_ISA(StructType) }; +struct IRClassType : IRType +{ + IRInstList<IRStructField> getFields() { return IRInstList<IRStructField>(getChildren()); } + + IR_LEAF_ISA(ClassType) +}; + struct IRAssociatedType : IRType { IR_LEAF_ISA(AssociatedType) @@ -1787,12 +1794,6 @@ void dumpIR(IRModule* module, const IRDumpOptions& options, char const* label, S /// True if the op type can be handled 'nominally' meaning that pointer identity is applicable. bool isNominalOp(IROp op); - // True if ptrType is a pointer type to elementType -bool isPointerOfType(IRInst* ptrType, IRInst* elementType); - - // True if ptrType is a pointer type to a type of opCode -bool isPointerOfType(IRInst* ptrType, IROp opCode); - // True if the IR inst represents a builtin object (e.g. __BuiltinFloatingPointType). bool isBuiltin(IRInst* inst); diff --git a/source/slang/slang-lower-to-ir.cpp b/source/slang/slang-lower-to-ir.cpp index e65bcc8e3..628f37c5b 100644 --- a/source/slang/slang-lower-to-ir.cpp +++ b/source/slang/slang-lower-to-ir.cpp @@ -5868,7 +5868,7 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> if(auto superDeclRefType = as<DeclRefType>(superType)) { - if( auto superStructDeclRef = superDeclRefType->declRef.as<StructDecl>() ) + if( superDeclRefType->declRef.as<StructDecl>() || superDeclRefType->declRef.as<ClassDecl>() ) { // TODO: the witness that a type inherits from a `struct` // type should probably be a key that will be used for @@ -6697,16 +6697,30 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> // Emit any generics that should wrap the actual type. auto outerGeneric = emitOuterGenerics(subContext, decl, decl); - IRStructType* irStruct = subBuilder->createStructType(); - addNameHint(context, irStruct, decl); - addLinkageDecoration(context, irStruct, decl); + IRType* irAggType = nullptr; + if (as<StructDecl>(decl)) + { + irAggType = subBuilder->createStructType(); + } + else if (as<ClassDecl>(decl)) + { + irAggType = subBuilder->createClassType(); + } + else + { + getSink()->diagnose(decl->loc, Diagnostics::unimplemented, "lower unknown AggType to IR"); + return LoweredValInfo::simple(subBuilder->getVoidType()); + } + + addNameHint(context, irAggType, decl); + addLinkageDecoration(context, irAggType, decl); if( auto payloadAttribute = decl->findModifier<PayloadAttribute>() ) { - subBuilder->addDecoration(irStruct, kIROp_PayloadDecoration); + subBuilder->addDecoration(irAggType, kIROp_PayloadDecoration); } - subBuilder->setInsertInto(irStruct); + subBuilder->setInsertInto(irAggType); // A `struct` that inherits from another `struct` must start // with a member for the direct base type. @@ -6718,12 +6732,13 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> auto superType = inheritanceDecl->base; if(auto superDeclRefType = as<DeclRefType>(superType)) { - if(auto superStructDeclRef = superDeclRefType->declRef.as<StructDecl>()) + if (superDeclRefType->declRef.as<StructDecl>() || + superDeclRefType->declRef.as<ClassDecl>()) { auto superKey = (IRStructKey*) getSimpleVal(context, ensureDecl(context, inheritanceDecl)); auto irSuperType = lowerType(context, superType.type); subBuilder->createStructField( - irStruct, + irAggType, superKey, irSuperType); } @@ -6758,7 +6773,7 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> // Then, the parent `struct` instruction itself will have // a "field" instruction. subBuilder->createStructField( - irStruct, + irAggType, fieldKey, fieldType); } @@ -6770,10 +6785,10 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> // Instead we will force emission of all children of aggregate // type declarations later, from the top-level emit logic. - irStruct->moveToEnd(); - addTargetIntrinsicDecorations(irStruct, decl); + irAggType->moveToEnd(); + addTargetIntrinsicDecorations(irAggType, decl); - return LoweredValInfo::simple(finishOuterGenerics(subBuilder, irStruct, outerGeneric)); + return LoweredValInfo::simple(finishOuterGenerics(subBuilder, irAggType, outerGeneric)); } void lowerRayPayloadAccessModifier(IRInst* inst, RayPayloadAccessSemantic* semantic, IROp op) @@ -7443,6 +7458,19 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> return finishOuterGenerics(funcTypeBuilder, irFuncType, outerGenerics); } + bool isClassType(IRType* type) + { + if (auto specialize = as<IRSpecialize>(type)) + { + return findSpecializeReturnVal(specialize)->getOp() == kIROp_ClassType; + } + else if (auto genericInst = as<IRGeneric>(type)) + { + return findGenericReturnVal(genericInst)->getOp() == kIROp_ClassType; + } + return type->getOp() == kIROp_ClassType; + } + LoweredValInfo lowerFuncDecl(FunctionDeclBase* decl) { // We are going to use a nested builder, because we will @@ -7654,6 +7682,13 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> { auto thisVar = subContext->irBuilder->emitVar(irResultType); subContext->thisVal = LoweredValInfo::ptr(thisVar); + + // For class-typed objects, we need to allocate it from heap. + if (isClassType(irResultType)) + { + auto allocatedObj = subContext->irBuilder->emitAllocObj(irResultType); + subContext->irBuilder->emitStore(thisVar, allocatedObj); + } } // We lower whatever statement was stored on the declaration diff --git a/source/slang/slang-parser.cpp b/source/slang/slang-parser.cpp index a2a249f7e..dbf329e9a 100644 --- a/source/slang/slang-parser.cpp +++ b/source/slang/slang-parser.cpp @@ -2260,36 +2260,10 @@ namespace Slang } else if( parser->LookAheadToken("class") ) { - // TODO(JS): Class type doesn't currently have the correct semantics. This is covered here - // https://github.com/shader-slang/slang/issues/2206 - // - // For now the use of `class` is disabled. - // The remaining code around `class` left intact as likely will be the basis for the future - // implementation. - - const bool disableClass = true; - - if (disableClass) - { - parser->sink->diagnose(parser->tokenReader.peekLoc(), Diagnostics::classIsReservedKeyword); - - // Consume `class` - advanceToken(parser); - - // Indicate in recovering state. - parser->isRecovering = true; - - // Check to confirm the result is invalid - SLANG_ASSERT(typeSpec.decl == nullptr && typeSpec.expr == nullptr); - return typeSpec; - } - else - { - auto decl = parser->ParseClass(); - typeSpec.decl = decl; - typeSpec.expr = createDeclRefType(parser, decl); - return typeSpec; - } + auto decl = parser->ParseClass(); + typeSpec.decl = decl; + typeSpec.expr = createDeclRefType(parser, decl); + return typeSpec; } else if(parser->LookAheadToken("enum")) { @@ -5852,8 +5826,30 @@ namespace Slang switch( tokenType ) { default: + if (parser->LookAheadToken("new")) + { + NewExpr* newExpr = parser->astBuilder->create<NewExpr>(); + parser->FillPosition(newExpr); + parser->ReadToken(); + auto subExpr = parsePostfixExpr(parser); + if (as<VarExpr>(subExpr) || as<GenericAppExpr>(subExpr)) + { + newExpr->functionExpr = subExpr; + } + else if (auto invokeExpr = as<InvokeExpr>(subExpr)) + { + newExpr->functionExpr = invokeExpr->functionExpr; + newExpr->arguments = invokeExpr->arguments; + newExpr->argumentDelimeterLocs = invokeExpr->argumentDelimeterLocs; + } + else + { + parser->diagnose(newExpr->loc, Diagnostics::syntaxError); + newExpr->functionExpr = parser->astBuilder->create<IncompleteExpr>(); + } + return newExpr; + } return parsePostfixExpr(parser); - case TokenType::OpNot: case TokenType::OpInc: case TokenType::OpDec: |
