diff options
Diffstat (limited to 'source')
26 files changed, 907 insertions, 437 deletions
diff --git a/source/slang/diff.meta.slang b/source/slang/diff.meta.slang index 31ed5845e..6f4888a5d 100644 --- a/source/slang/diff.meta.slang +++ b/source/slang/diff.meta.slang @@ -26,7 +26,7 @@ __attributeTarget(FunctionDeclBase) attribute_syntax [NoDiffThis] : NoDiffThisAttribute; // A 'none-type' that acts as a run-time sentinel for zero differentials. -public struct NullDifferential : IDifferentiable +export struct NullDifferential : IDifferentiable { // for now, we'll use at least one field to make sure the type is non-empty uint dummy; diff --git a/source/slang/glsl.meta.slang b/source/slang/glsl.meta.slang index 98f30cd3c..a43a7ba3c 100644 --- a/source/slang/glsl.meta.slang +++ b/source/slang/glsl.meta.slang @@ -2,385 +2,385 @@ // From the GLSL spec, section 4.1. 'asic Types' // -typealias vec2 = vector<float, 2>; -typealias vec3 = vector<float, 3>; -typealias vec4 = vector<float, 4>; - -typealias dvec2 = vector<double, 2>; -typealias dvec3 = vector<double, 3>; -typealias dvec4 = vector<double, 4>; - -typealias bvec2 = vector<bool, 2>; -typealias bvec3 = vector<bool, 3>; -typealias bvec4 = vector<bool, 4>; - -typealias ivec2 = vector<int, 2>; -typealias ivec3 = vector<int, 3>; -typealias ivec4 = vector<int, 4>; - -typealias uvec2 = vector<uint, 2>; -typealias uvec3 = vector<uint, 3>; -typealias uvec4 = vector<uint, 4>; - -typealias i8vec2 = vector<int8_t, 2>; -typealias i8vec3 = vector<int8_t, 3>; -typealias i8vec4 = vector<int8_t, 4>; - -typealias u8vec2 = vector<uint8_t, 2>; -typealias u8vec3 = vector<uint8_t, 3>; -typealias u8vec4 = vector<uint8_t, 4>; - -typealias i16vec2 = vector<int16_t, 2>; -typealias i16vec3 = vector<int16_t, 3>; -typealias i16vec4 = vector<int16_t, 4>; - -typealias u16vec2 = vector<uint16_t, 2>; -typealias u16vec3 = vector<uint16_t, 3>; -typealias u16vec4 = vector<uint16_t, 4>; - -typealias i64vec2 = vector<int64_t, 2>; -typealias i64vec3 = vector<int64_t, 3>; -typealias i64vec4 = vector<int64_t, 4>; - -typealias u64vec2 = vector<uint64_t, 2>; -typealias u64vec3 = vector<uint64_t, 3>; -typealias u64vec4 = vector<uint64_t, 4>; - -typealias mat2 = matrix<float, 2, 2>; -typealias mat3 = matrix<float, 3, 3>; -typealias mat4 = matrix<float, 4, 4>; - -typealias mat2x2 = matrix<float, 2, 2>; -typealias mat2x3 = matrix<float, 3, 2>; -typealias mat2x4 = matrix<float, 4, 2>; - -typealias mat3x2 = matrix<float, 2, 3>; -typealias mat3x3 = matrix<float, 3, 3>; -typealias mat3x4 = matrix<float, 4, 3>; - -typealias mat4x2 = matrix<float, 2, 4>; -typealias mat4x3 = matrix<float, 3, 4>; -typealias mat4x4 = matrix<float, 4, 4>; - -typealias dmat2 = matrix<double, 2, 2>; -typealias dmat3 = matrix<double, 3, 3>; -typealias dmat4 = matrix<double, 4, 4>; - -typealias dmat2x2 = matrix<double, 2, 2>; -typealias dmat2x3 = matrix<double, 3, 2>; -typealias dmat2x4 = matrix<double, 4, 2>; - -typealias dmat3x2 = matrix<double, 2, 3>; -typealias dmat3x3 = matrix<double, 3, 3>; -typealias dmat3x4 = matrix<double, 4, 3>; - -typealias dmat4x2 = matrix<double, 2, 4>; -typealias dmat4x3 = matrix<double, 3, 4>; -typealias dmat4x4 = matrix<double, 4, 4>; - -typealias usampler1D = Sampler1D<uint4>; -typealias isampler1D = Sampler1D<int4>; -typealias sampler1D = Sampler1D<float4>; - -typealias usampler2D = Sampler2D<uint4>; -typealias isampler2D = Sampler2D<int4>; -typealias sampler2D = Sampler2D<float4>; - -typealias usampler3D = Sampler3D<uint4>; -typealias isampler3D = Sampler3D<int4>; -typealias sampler3D = Sampler3D<float4>; - -typealias usamplerCube = SamplerCube<uint4>; -typealias isamplerCube = SamplerCube<int4>; -typealias samplerCube = SamplerCube<float4>; - -typealias Sampler1DShadow<T=float> = __TextureImpl<T, __Shape1D, /*isArray:*/ 0, /*isMS:*/ 0, /*sampleCount:*/ 0, /*access:*/ 0, /*isShadow: */ 1, /*isCombined: */ 1, /*format*/ 0>; -typealias usampler1DShadow = Sampler1DShadow<uint>; -typealias isampler1DShadow = Sampler1DShadow<int>; -typealias sampler1DShadow = Sampler1DShadow<float>; - -typealias Sampler2DShadow<T=float> = __TextureImpl<T, __Shape2D, /*isArray:*/ 0, /*isMS:*/ 0, /*sampleCount:*/ 0, /*access:*/ 0, /*isShadow: */ 1, /*isCombined: */ 1, /*format*/ 0>; -typealias usampler2DShadow = Sampler2DShadow<uint>; -typealias isampler2DShadow = Sampler2DShadow<int>; -typealias sampler2DShadow = Sampler2DShadow<float>; - -typealias SamplerCubeShadow<T=float> = __TextureImpl<T, __ShapeCube, /*isArray:*/ 0, /*isMS:*/ 0, /*sampleCount:*/ 0, /*access:*/ 0, /*isShadow: */ 1, /*isCombined: */ 1, /*format*/ 0>; -typealias usamplerCubeShadow = SamplerCubeShadow<uint>; -typealias isamplerCubeShadow = SamplerCubeShadow<int>; -typealias samplerCubeShadow = SamplerCubeShadow<float>; - -typealias usampler1DArray = Sampler1DArray<uint4>; -typealias isampler1DArray = Sampler1DArray<int4>; -typealias sampler1DArray = Sampler1DArray<float4>; - -typealias usampler2DArray = Sampler2DArray<uint4>; -typealias isampler2DArray = Sampler2DArray<int4>; -typealias sampler2DArray = Sampler2DArray<float4>; - -typealias usamplerCubeArray = SamplerCubeArray<uint4>; -typealias isamplerCubeArray = SamplerCubeArray<int4>; -typealias samplerCubeArray = SamplerCubeArray<float4>; - -typealias Sampler1DArrayShadow<T=float> = __TextureImpl<T, __Shape1D, /*isArray:*/ 1, /*isMS:*/ 0, /*sampleCount:*/ 0, /*access:*/ 0, /*isShadow: */ 1, /*isCombined: */ 1, /*format*/ 0>; -typealias usampler1DArrayShadow = Sampler1DArrayShadow<uint>; -typealias isampler1DArrayShadow = Sampler1DArrayShadow<int>; -typealias sampler1DArrayShadow = Sampler1DArrayShadow<float>; +public typealias vec2 = vector<float, 2>; +public typealias vec3 = vector<float, 3>; +public typealias vec4 = vector<float, 4>; + +public typealias dvec2 = vector<double, 2>; +public typealias dvec3 = vector<double, 3>; +public typealias dvec4 = vector<double, 4>; + +public typealias bvec2 = vector<bool, 2>; +public typealias bvec3 = vector<bool, 3>; +public typealias bvec4 = vector<bool, 4>; + +public typealias ivec2 = vector<int, 2>; +public typealias ivec3 = vector<int, 3>; +public typealias ivec4 = vector<int, 4>; + +public typealias uvec2 = vector<uint, 2>; +public typealias uvec3 = vector<uint, 3>; +public typealias uvec4 = vector<uint, 4>; + +public typealias i8vec2 = vector<int8_t, 2>; +public typealias i8vec3 = vector<int8_t, 3>; +public typealias i8vec4 = vector<int8_t, 4>; + +public typealias u8vec2 = vector<uint8_t, 2>; +public typealias u8vec3 = vector<uint8_t, 3>; +public typealias u8vec4 = vector<uint8_t, 4>; + +public typealias i16vec2 = vector<int16_t, 2>; +public typealias i16vec3 = vector<int16_t, 3>; +public typealias i16vec4 = vector<int16_t, 4>; + +public typealias u16vec2 = vector<uint16_t, 2>; +public typealias u16vec3 = vector<uint16_t, 3>; +public typealias u16vec4 = vector<uint16_t, 4>; + +public typealias i64vec2 = vector<int64_t, 2>; +public typealias i64vec3 = vector<int64_t, 3>; +public typealias i64vec4 = vector<int64_t, 4>; + +public typealias u64vec2 = vector<uint64_t, 2>; +public typealias u64vec3 = vector<uint64_t, 3>; +public typealias u64vec4 = vector<uint64_t, 4>; + +public typealias mat2 = matrix<float, 2, 2>; +public typealias mat3 = matrix<float, 3, 3>; +public typealias mat4 = matrix<float, 4, 4>; + +public typealias mat2x2 = matrix<float, 2, 2>; +public typealias mat2x3 = matrix<float, 3, 2>; +public typealias mat2x4 = matrix<float, 4, 2>; + +public typealias mat3x2 = matrix<float, 2, 3>; +public typealias mat3x3 = matrix<float, 3, 3>; +public typealias mat3x4 = matrix<float, 4, 3>; + +public typealias mat4x2 = matrix<float, 2, 4>; +public typealias mat4x3 = matrix<float, 3, 4>; +public typealias mat4x4 = matrix<float, 4, 4>; + +public typealias dmat2 = matrix<double, 2, 2>; +public typealias dmat3 = matrix<double, 3, 3>; +public typealias dmat4 = matrix<double, 4, 4>; + +public typealias dmat2x2 = matrix<double, 2, 2>; +public typealias dmat2x3 = matrix<double, 3, 2>; +public typealias dmat2x4 = matrix<double, 4, 2>; + +public typealias dmat3x2 = matrix<double, 2, 3>; +public typealias dmat3x3 = matrix<double, 3, 3>; +public typealias dmat3x4 = matrix<double, 4, 3>; + +public typealias dmat4x2 = matrix<double, 2, 4>; +public typealias dmat4x3 = matrix<double, 3, 4>; +public typealias dmat4x4 = matrix<double, 4, 4>; + +public typealias usampler1D = Sampler1D<uint4>; +public typealias isampler1D = Sampler1D<int4>; +public typealias sampler1D = Sampler1D<float4>; + +public typealias usampler2D = Sampler2D<uint4>; +public typealias isampler2D = Sampler2D<int4>; +public typealias sampler2D = Sampler2D<float4>; + +public typealias usampler3D = Sampler3D<uint4>; +public typealias isampler3D = Sampler3D<int4>; +public typealias sampler3D = Sampler3D<float4>; + +public typealias usamplerCube = SamplerCube<uint4>; +public typealias isamplerCube = SamplerCube<int4>; +public typealias samplerCube = SamplerCube<float4>; + +public typealias Sampler1DShadow<T=float> = __TextureImpl<T, __Shape1D, /*isArray:*/ 0, /*isMS:*/ 0, /*sampleCount:*/ 0, /*access:*/ 0, /*isShadow: */ 1, /*isCombined: */ 1, /*format*/ 0>; +public typealias usampler1DShadow = Sampler1DShadow<uint>; +public typealias isampler1DShadow = Sampler1DShadow<int>; +public typealias sampler1DShadow = Sampler1DShadow<float>; + +public typealias Sampler2DShadow<T=float> = __TextureImpl<T, __Shape2D, /*isArray:*/ 0, /*isMS:*/ 0, /*sampleCount:*/ 0, /*access:*/ 0, /*isShadow: */ 1, /*isCombined: */ 1, /*format*/ 0>; +public typealias usampler2DShadow = Sampler2DShadow<uint>; +public typealias isampler2DShadow = Sampler2DShadow<int>; +public typealias sampler2DShadow = Sampler2DShadow<float>; + +public typealias SamplerCubeShadow<T=float> = __TextureImpl<T, __ShapeCube, /*isArray:*/ 0, /*isMS:*/ 0, /*sampleCount:*/ 0, /*access:*/ 0, /*isShadow: */ 1, /*isCombined: */ 1, /*format*/ 0>; +public typealias usamplerCubeShadow = SamplerCubeShadow<uint>; +public typealias isamplerCubeShadow = SamplerCubeShadow<int>; +public typealias samplerCubeShadow = SamplerCubeShadow<float>; + +public typealias usampler1DArray = Sampler1DArray<uint4>; +public typealias isampler1DArray = Sampler1DArray<int4>; +public typealias sampler1DArray = Sampler1DArray<float4>; + +public typealias usampler2DArray = Sampler2DArray<uint4>; +public typealias isampler2DArray = Sampler2DArray<int4>; +public typealias sampler2DArray = Sampler2DArray<float4>; + +public typealias usamplerCubeArray = SamplerCubeArray<uint4>; +public typealias isamplerCubeArray = SamplerCubeArray<int4>; +public typealias samplerCubeArray = SamplerCubeArray<float4>; + +public typealias Sampler1DArrayShadow<T=float> = __TextureImpl<T, __Shape1D, /*isArray:*/ 1, /*isMS:*/ 0, /*sampleCount:*/ 0, /*access:*/ 0, /*isShadow: */ 1, /*isCombined: */ 1, /*format*/ 0>; +public typealias usampler1DArrayShadow = Sampler1DArrayShadow<uint>; +public typealias isampler1DArrayShadow = Sampler1DArrayShadow<int>; +public typealias sampler1DArrayShadow = Sampler1DArrayShadow<float>; -typealias Sampler2DArrayShadow<T=float> = __TextureImpl<T, __Shape2D, /*isArray:*/ 1, /*isMS:*/ 0, /*sampleCount:*/ 0, /*access:*/ 0, /*isShadow: */ 1, /*isCombined: */ 1, /*format*/ 0>; -typealias usampler2DArrayShadow = Sampler2DArrayShadow<uint>; -typealias isampler2DArrayShadow = Sampler2DArrayShadow<int>; -typealias sampler2DArrayShadow = Sampler2DArrayShadow<float>; - -typealias SamplerCubeArrayShadow<T=float> = __TextureImpl<T, __ShapeCube, /*isArray:*/ 1, /*isMS:*/ 0, /*sampleCount:*/ 0, /*access:*/ 0, /*isShadow: */ 1, /*isCombined: */ 1, /*format*/ 0>; -typealias usamplerCubeArrayShadow = SamplerCubeArrayShadow<uint>; -typealias isamplerCubeArrayShadow = SamplerCubeArrayShadow<int>; -typealias samplerCubeArrayShadow = SamplerCubeArrayShadow<float>; +public typealias Sampler2DArrayShadow<T=float> = __TextureImpl<T, __Shape2D, /*isArray:*/ 1, /*isMS:*/ 0, /*sampleCount:*/ 0, /*access:*/ 0, /*isShadow: */ 1, /*isCombined: */ 1, /*format*/ 0>; +public typealias usampler2DArrayShadow = Sampler2DArrayShadow<uint>; +public typealias isampler2DArrayShadow = Sampler2DArrayShadow<int>; +public typealias sampler2DArrayShadow = Sampler2DArrayShadow<float>; + +public typealias SamplerCubeArrayShadow<T=float> = __TextureImpl<T, __ShapeCube, /*isArray:*/ 1, /*isMS:*/ 0, /*sampleCount:*/ 0, /*access:*/ 0, /*isShadow: */ 1, /*isCombined: */ 1, /*format*/ 0>; +public typealias usamplerCubeArrayShadow = SamplerCubeArrayShadow<uint>; +public typealias isamplerCubeArrayShadow = SamplerCubeArrayShadow<int>; +public typealias samplerCubeArrayShadow = SamplerCubeArrayShadow<float>; [ForceInline] -vector<T,4> texelFetch<T:__BuiltinArithmeticType, let N : int> (Sampler1D<vector<T,N>> sampler, int p, int lod) +public vector<T,4> texelFetch<T:__BuiltinArithmeticType, let N : int> (Sampler1D<vector<T,N>> sampler, int p, int lod) { return __vectorReshape<4>(sampler.Load(int2(p, lod))); } [ForceInline] -vector<T,4> texelFetch<T:__BuiltinArithmeticType, let N : int> (Sampler2D<vector<T,N>> sampler, ivec2 p, int lod) +public vector<T,4> texelFetch<T:__BuiltinArithmeticType, let N : int> (Sampler2D<vector<T,N>> sampler, ivec2 p, int lod) { return __vectorReshape<4>(sampler.Load(int3(p, lod))); } [ForceInline] -vector<T,4> texelFetch<T:__BuiltinArithmeticType, let N : int> (Sampler3D<vector<T,N>> sampler, ivec3 p, int lod) +public vector<T,4> texelFetch<T:__BuiltinArithmeticType, let N : int> (Sampler3D<vector<T,N>> sampler, ivec3 p, int lod) { return __vectorReshape<4>(sampler.Load(int4(p, lod))); } [ForceInline] -vector<T,4> texelFetch<T:__BuiltinArithmeticType, let N : int> (Sampler1DArray<vector<T,N>> sampler, ivec2 p, int lod) +public vector<T,4> texelFetch<T:__BuiltinArithmeticType, let N : int> (Sampler1DArray<vector<T,N>> sampler, ivec2 p, int lod) { return __vectorReshape<4>(sampler.Load(int3(p, lod))); } [ForceInline] -vector<T,4> texelFetch<T:__BuiltinArithmeticType, let N : int> (Sampler2DArray<vector<T,N>> sampler, ivec3 p, int lod) +public vector<T,4> texelFetch<T:__BuiltinArithmeticType, let N : int> (Sampler2DArray<vector<T,N>> sampler, ivec3 p, int lod) { return __vectorReshape<4>(sampler.Load(int4(p, lod))); } [ForceInline] -vector<T,4> texture<T:__BuiltinArithmeticType, let N : int> (Sampler1D<vector<T,N>> sampler, float p, float bias = 0.0) +public vector<T,4> texture<T:__BuiltinArithmeticType, let N : int> (Sampler1D<vector<T,N>> sampler, float p, float bias = 0.0) { return __vectorReshape<4>(sampler.SampleBias(p, bias)); } [ForceInline] -vector<T,4> texture<T:__BuiltinArithmeticType, let N : int> (Sampler2D<vector<T,N>> sampler, float2 p, float bias = 0.0) +public vector<T,4> texture<T:__BuiltinArithmeticType, let N : int> (Sampler2D<vector<T,N>> sampler, float2 p, float bias = 0.0) { return __vectorReshape<4>(sampler.SampleBias(p, bias)); } [ForceInline] -vector<T,4> texture<T:__BuiltinArithmeticType, let N : int> (Sampler3D<vector<T,N>> sampler, float3 p, float bias = 0.0) +public vector<T,4> texture<T:__BuiltinArithmeticType, let N : int> (Sampler3D<vector<T,N>> sampler, float3 p, float bias = 0.0) { return __vectorReshape<4>(sampler.SampleBias(p, bias)); } [ForceInline] -vector<T,4> texture<T:__BuiltinArithmeticType, let N : int> (SamplerCube<vector<T,N>> sampler, float3 p, float bias = 0.0) +public vector<T,4> texture<T:__BuiltinArithmeticType, let N : int> (SamplerCube<vector<T,N>> sampler, float3 p, float bias = 0.0) { return __vectorReshape<4>(sampler.SampleBias(p, bias)); } [ForceInline] -float texture<T:__BuiltinArithmeticType, let N : int> (Sampler1DShadow<vector<T,N>> sampler, float2 p) +public float texture<T:__BuiltinArithmeticType, let N : int> (Sampler1DShadow<vector<T,N>> sampler, float2 p) { return sampler.SampleCmp(p.x, p.y); } [ForceInline] -float texture<T:__BuiltinArithmeticType, let N : int> (Sampler2DShadow<vector<T,N>> sampler, float3 p) +public float texture<T:__BuiltinArithmeticType, let N : int> (Sampler2DShadow<vector<T,N>> sampler, float3 p) { return sampler.SampleCmp(p.xy, p.z); } [ForceInline] -float texture<T:__BuiltinArithmeticType, let N : int> (SamplerCubeShadow<vector<T,N>> sampler, float4 p) +public float texture<T:__BuiltinArithmeticType, let N : int> (SamplerCubeShadow<vector<T,N>> sampler, float4 p) { return sampler.SampleCmp(p.xyz, p.w); } [ForceInline] -vector<T,4> texture<T:__BuiltinArithmeticType, let N : int> (Sampler1DArray<vector<T,N>> sampler, float2 p, float bias = 0.0) +public vector<T,4> texture<T:__BuiltinArithmeticType, let N : int> (Sampler1DArray<vector<T,N>> sampler, float2 p, float bias = 0.0) { return __vectorReshape<4>(sampler.SampleBias(p, bias)); } [ForceInline] -vector<T,4> texture<T:__BuiltinArithmeticType, let N : int> (Sampler2DArray<vector<T,N>> sampler, float3 p, float bias = 0.0) +public vector<T,4> texture<T:__BuiltinArithmeticType, let N : int> (Sampler2DArray<vector<T,N>> sampler, float3 p, float bias = 0.0) { return __vectorReshape<4>(sampler.SampleBias(p, bias)); } [ForceInline] -vector<T,4> texture<T:__BuiltinArithmeticType, let N : int> (SamplerCubeArray<vector<T,N>> sampler, float4 p, float bias = 0.0) +public vector<T,4> texture<T:__BuiltinArithmeticType, let N : int> (SamplerCubeArray<vector<T,N>> sampler, float4 p, float bias = 0.0) { return __vectorReshape<4>(sampler.SampleBias(p, bias)); } [ForceInline] -float texture<T:__BuiltinArithmeticType, let N : int> (Sampler1DArrayShadow<vector<T,N>> sampler, float3 p) +public float texture<T:__BuiltinArithmeticType, let N : int> (Sampler1DArrayShadow<vector<T,N>> sampler, float3 p) { return sampler.SampleCmp(p.xy, p.z); } [ForceInline] -float texture<T:__BuiltinArithmeticType, let N : int> (Sampler2DArrayShadow<vector<T,N>> sampler, float4 p) +public float texture<T:__BuiltinArithmeticType, let N : int> (Sampler2DArrayShadow<vector<T,N>> sampler, float4 p) { return sampler.SampleCmp(p.xyz, p.w); } __generic<T:__BuiltinArithmeticType, let N : int, shape:__ITextureShape, let sampleCount: int, let isArray:int, let format:int> -vector<T,4> textureGrad(__TextureImpl<vector<T,N>, shape, isArray, 0, sampleCount, 0, 1, 1, format> sampler, vector<float, shape.dimensions+isArray> P, vector<float,shape.planeDimensions> dPdx, vector<float,shape.planeDimensions> dPdy) +public vector<T,4> textureGrad(__TextureImpl<vector<T,N>, shape, isArray, 0, sampleCount, 0, 1, 1, format> sampler, vector<float, shape.dimensions+isArray> P, vector<float,shape.planeDimensions> dPdx, vector<float,shape.planeDimensions> dPdy) { return __vectorReshape<4>(sampler.SampleGrad(P, dPdx, dPdy)); } -out float4 gl_Position : SV_Position; -out float gl_PointSize : SV_PointSize; -in vec4 gl_FragCoord : SV_Position; -out float gl_FragDepth : SV_Depth; -out int gl_FragStencilRef : SV_StencilRef; +public out float4 gl_Position : SV_Position; +public out float gl_PointSize : SV_PointSize; +public in vec4 gl_FragCoord : SV_Position; +public out float gl_FragDepth : SV_Depth; +public out int gl_FragStencilRef : SV_StencilRef; -in uvec3 gl_GlobalInvocationID : SV_DispatchThreadID; -in uvec3 gl_WorkGroupID : SV_GroupID; -in uvec3 gl_LocalInvocationIndex : SV_GroupIndex; -in uvec3 gl_LocalInvocationID : SV_GroupThreadID; +public in uvec3 gl_GlobalInvocationID : SV_DispatchThreadID; +public in uvec3 gl_WorkGroupID : SV_GroupID; +public in uvec3 gl_LocalInvocationIndex : SV_GroupIndex; +public in uvec3 gl_LocalInvocationID : SV_GroupThreadID; // TODO: define overload for tessellation control stage. -in int gl_InvocationID : SV_GSInstanceID; +public in int gl_InvocationID : SV_GSInstanceID; -in int gl_InstanceIndex : SV_InstanceID; -in bool gl_FrontFacing : SV_IsFrontFace; +public in int gl_InstanceIndex : SV_InstanceID; +public in bool gl_FrontFacing : SV_IsFrontFace; // TODO: define overload for geometry stage. -in int gl_Layer : SV_RenderTargetArrayIndex; +public in int gl_Layer : SV_RenderTargetArrayIndex; -in int gl_SampleID : SV_SampleIndex; -in int gl_VertexIndex : SV_VertexID; -in int gl_ViewIndex : SV_ViewID; -in int gl_ViewportIndex : SV_ViewportArrayIndex; +public in int gl_SampleID : SV_SampleIndex; +public in int gl_VertexIndex : SV_VertexID; +public in int gl_ViewIndex : SV_ViewID; +public in int gl_ViewportIndex : SV_ViewportArrayIndex; // Override operator* behavior to compute algebric product of matrices and vectors. [OverloadRank(15)] [ForceInline] -matrix<float, N, N> operator*<let N : int>(matrix<float, N, N> m1, matrix<float, N, N> m2) +public matrix<float, N, N> operator*<let N : int>(matrix<float, N, N> m1, matrix<float, N, N> m2) { return mul(m2, m1); } [OverloadRank(15)] [ForceInline] -matrix<half, N, N> operator*<let N : int>(matrix<half, N, N> m1, matrix<half, N, N> m2) +public matrix<half, N, N> operator*<let N : int>(matrix<half, N, N> m1, matrix<half, N, N> m2) { return mul(m2, m1); } [OverloadRank(15)] [ForceInline] -matrix<double, N, N> operator*<let N : int>(matrix<double, N, N> m1, matrix<double, N, N> m2) +public matrix<double, N, N> operator*<let N : int>(matrix<double, N, N> m1, matrix<double, N, N> m2) { return mul(m2, m1); } [ForceInline] [OverloadRank(15)] -matrix<T, R, L> operator*<T:__BuiltinFloatingPointType, let L : int, let C : int, let R : int>(matrix<T, C, L> m1, matrix<T, R, C> m2) +public matrix<T, R, L> operator*<T:__BuiltinFloatingPointType, let L : int, let C : int, let R : int>(matrix<T, C, L> m1, matrix<T, R, C> m2) { return mul(m2, m1); } [ForceInline] [OverloadRank(15)] -vector<T, R> operator*<T:__BuiltinFloatingPointType, let C : int, let R : int>(vector<T, C> v, matrix<T, R, C> m) +public vector<T, R> operator*<T:__BuiltinFloatingPointType, let C : int, let R : int>(vector<T, C> v, matrix<T, R, C> m) { return mul(m, v); } [ForceInline] [OverloadRank(15)] -vector<T, C> operator*<T:__BuiltinFloatingPointType, let C : int, let R : int>(matrix<T, R, C> m, vector<T, R> v) +public vector<T, C> operator*<T:__BuiltinFloatingPointType, let C : int, let R : int>(matrix<T, R, C> m, vector<T, R> v) { return mul(v, m); } __intrinsic_op(mul) -matrix<T, N, M> matrixCompMult<T:__BuiltinFloatingPointType, let N : int, let M : int>(matrix<T,N,M> left, matrix<T,N,M> right); +public matrix<T, N, M> matrixCompMult<T:__BuiltinFloatingPointType, let N : int, let M : int>(matrix<T,N,M> left, matrix<T,N,M> right); __intrinsic_op(cmpLE) -vector<bool, N> lessThanEqual<T, let N:int>(vector<T, N> x, vector<T, N> y); +public vector<bool, N> lessThanEqual<T, let N:int>(vector<T, N> x, vector<T, N> y); __intrinsic_op(cmpLT) -vector<bool, N> lessThan<T, let N:int>(vector<T, N> x, vector<T, N> y); +public vector<bool, N> lessThan<T, let N:int>(vector<T, N> x, vector<T, N> y); __intrinsic_op(cmpGT) -vector<bool, N> greaterThan<T, let N:int>(vector<T, N> x, vector<T, N> y); +public vector<bool, N> greaterThan<T, let N:int>(vector<T, N> x, vector<T, N> y); __intrinsic_op(cmpGE) -vector<bool, N> greaterThanEqual<T, let N:int>(vector<T, N> x, vector<T, N> y); +public vector<bool, N> greaterThanEqual<T, let N:int>(vector<T, N> x, vector<T, N> y); __intrinsic_op(cmpEQ) -vector<bool, N> equal<T, let N:int>(vector<T, N> x, vector<T, N> y); +public vector<bool, N> equal<T, let N:int>(vector<T, N> x, vector<T, N> y); __intrinsic_op(cmpNE) -vector<bool, N> notEqual<T, let N:int>(vector<T, N> x, vector<T, N> y); +public vector<bool, N> notEqual<T, let N:int>(vector<T, N> x, vector<T, N> y); __generic<T> -extension vector<T, 2> +public extension vector<T, 2> { - [ForceInline] __init(vector<T, 3> bigger) { this = bigger.xy; } - [ForceInline] __init(vector<T, 4> bigger) { this = bigger.xy; } + [ForceInline] public __init(vector<T, 3> bigger) { this = bigger.xy; } + [ForceInline] public __init(vector<T, 4> bigger) { this = bigger.xy; } } __generic<T> -extension vector<T, 3> +public extension vector<T, 3> { - [ForceInline] __init(vector<T, 4> bigger) { this = bigger.xyz; } + [ForceInline] public __init(vector<T, 4> bigger) { this = bigger.xyz; } } [ForceInline] [OverloadRank(15)] -bool operator==<T:__BuiltinArithmeticType, let N : int>(vector<T, N> left, vector<T, N> right) +public bool operator==<T:__BuiltinArithmeticType, let N : int>(vector<T, N> left, vector<T, N> right) { return all(equal(left, right)); } [ForceInline] [OverloadRank(15)] -bool operator!=<T:__BuiltinArithmeticType, let N : int>(vector<T, N> left, vector<T, N> right) +public bool operator!=<T:__BuiltinArithmeticType, let N : int>(vector<T, N> left, vector<T, N> right) { return any(notEqual(left, right)); } [ForceInline] [OverloadRank(14)] -bool operator==<T:__BuiltinFloatingPointType, let N : int>(vector<T, N> left, vector<T, N> right) +public bool operator==<T:__BuiltinFloatingPointType, let N : int>(vector<T, N> left, vector<T, N> right) { return all(equal(left, right)); } [ForceInline] [OverloadRank(14)] -bool operator!=<T:__BuiltinFloatingPointType, let N : int>(vector<T, N> left, vector<T, N> right) +public bool operator!=<T:__BuiltinFloatingPointType, let N : int>(vector<T, N> left, vector<T, N> right) { return any(notEqual(left, right)); } [ForceInline] [OverloadRank(14)] -bool operator==<T:__BuiltinLogicalType, let N : int>(vector<T, N> left, vector<T, N> right) +public bool operator==<T:__BuiltinLogicalType, let N : int>(vector<T, N> left, vector<T, N> right) { return all(equal(left, right)); } [ForceInline] [OverloadRank(14)] -bool operator!=<T:__BuiltinLogicalType, let N : int>(vector<T, N> left, vector<T, N> right) +public bool operator!=<T:__BuiltinLogicalType, let N : int>(vector<T, N> left, vector<T, N> right) { return any(notEqual(left, right)); } @@ -392,14 +392,14 @@ for (auto type : kBaseTypes) { }}}} [ForceInline] [OverloadRank(15)] -bool operator==<let N : int>(vector<$(typeName), N> left, vector<$(typeName), N> right) +public bool operator==<let N : int>(vector<$(typeName), N> left, vector<$(typeName), N> right) { return all(equal(left, right)); } [ForceInline] [OverloadRank(15)] -bool operator!=<let N : int>(vector<$(typeName), N> left, vector<$(typeName), N> right) +public bool operator!=<let N : int>(vector<$(typeName), N> left, vector<$(typeName), N> right) { return any(notEqual(left, right)); } @@ -407,13 +407,13 @@ ${{{{ } }}}} -[ForceInline] int findLSB(int v) { return firstbitlow(v); } -[ForceInline] uint findLSB(uint v) { return firstbitlow(v); } -[ForceInline] vector<int,N> findLSB<let N:int>(vector<int,N> value) +[ForceInline] public int findLSB(int v) { return firstbitlow(v); } +[ForceInline] public uint findLSB(uint v) { return firstbitlow(v); } +[ForceInline] public vector<int,N> findLSB<let N:int>(vector<int,N> value) { return firstbitlow(value); } -[ForceInline] vector<uint,N> findLSB<let N:int>(vector<uint,N> value) +[ForceInline] public vector<uint,N> findLSB<let N:int>(vector<uint,N> value) { return firstbitlow(value); } diff --git a/source/slang/slang-ast-decl.h b/source/slang/slang-ast-decl.h index ddff39502..ab4fbaf17 100644 --- a/source/slang/slang-ast-decl.h +++ b/source/slang/slang-ast-decl.h @@ -426,6 +426,15 @@ class ModuleDecl : public NamespaceDeclBase /// OrderedDictionary<Decl*, RefPtr<DeclAssociationList>> mapDeclToAssociatedDecls; + /// Whether the module is defined in legacy language. + /// The legacy Slang language does not have visibility modifiers and everything is treated as + /// `public`. Newer version of the language introduces visibility and makes `internal` as the + /// default. To prevent this from breaking existing code, we need to know whether a module is + /// written in the legacy language. We detect this by checking whether the module has any + /// visibility modifiers, or if the module uses new language constructs, e.g. `module`, `__include`, + /// `__implementing` etc. + bool isInLegacyLanguage = true; + SLANG_UNREFLECTED /// Map a type to the list of extensions of that type (if any) declared in this module diff --git a/source/slang/slang-ast-modifier.h b/source/slang/slang-ast-modifier.h index 9ee3fea86..ae87c4e10 100644 --- a/source/slang/slang-ast-modifier.h +++ b/source/slang/slang-ast-modifier.h @@ -16,7 +16,10 @@ class ConstModifier : public Modifier { SLANG_AST_CLASS(ConstModifier)}; class InstanceModifier : public Modifier { SLANG_AST_CLASS(InstanceModifier)}; class BuiltinModifier : public Modifier { SLANG_AST_CLASS(BuiltinModifier)}; class InlineModifier : public Modifier { SLANG_AST_CLASS(InlineModifier)}; -class PublicModifier : public Modifier { SLANG_AST_CLASS(PublicModifier)}; +class VisibilityModifier : public Modifier {SLANG_AST_CLASS(VisibilityModifier)}; +class PublicModifier : public VisibilityModifier { SLANG_AST_CLASS(PublicModifier)}; +class PrivateModifier : public VisibilityModifier { SLANG_AST_CLASS(PrivateModifier) }; +class InternalModifier : public VisibilityModifier { SLANG_AST_CLASS(InternalModifier) }; class RequireModifier : public Modifier { SLANG_AST_CLASS(RequireModifier)}; class ParamModifier : public Modifier { SLANG_AST_CLASS(ParamModifier)}; class ExternModifier : public Modifier { SLANG_AST_CLASS(ExternModifier)}; diff --git a/source/slang/slang-ast-support-types.h b/source/slang/slang-ast-support-types.h index 5da19f377..1e71d0c4a 100644 --- a/source/slang/slang-ast-support-types.h +++ b/source/slang/slang-ast-support-types.h @@ -1598,7 +1598,13 @@ namespace Slang /// Get the operator name from the higher order invoke expr. UnownedStringSlice getHigherOrderOperatorName(HigherOrderInvokeExpr* expr); - + enum class DeclVisibility + { + Private, + Internal, + Public, + Default = Internal, + }; } // namespace Slang #endif diff --git a/source/slang/slang-check-conversion.cpp b/source/slang/slang-check-conversion.cpp index c2cfabcfe..d76b2a80e 100644 --- a/source/slang/slang-check-conversion.cpp +++ b/source/slang/slang-check-conversion.cpp @@ -1063,7 +1063,7 @@ namespace Slang overloadContext.argCount = 1; overloadContext.argTypes = &fromType.type; overloadContext.args = &fromExpr; - + overloadContext.sourceScope = m_outerScope; overloadContext.originalExpr = nullptr; if(fromExpr) { diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index b4cc6c00a..671bb26dd 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -298,7 +298,9 @@ namespace Slang { // Things at the global scope are always "members" of their module. // - if(as<ModuleDecl>(parentDecl)) + if(as<NamespaceDeclBase>(parentDecl)) + return false; + if (as<FileDecl>(parentDecl)) return false; // Anything explicitly marked `static` and not at module scope @@ -373,7 +375,7 @@ namespace Slang auto parentDecl = decl->parentDecl; if (auto genericDecl = as<GenericDecl>(parentDecl)) parentDecl = genericDecl->parentDecl; - return as<NamespaceDeclBase>(parentDecl) != nullptr; + return as<NamespaceDeclBase>(parentDecl) != nullptr || as<FileDecl>(parentDecl) != nullptr; } /// Is `decl` a global shader parameter declaration? @@ -385,7 +387,7 @@ namespace Slang // A global shader parameter must be declared at global or namespace // scope, so that it has a single definition across the module. // - if(!as<NamespaceDeclBase>(decl->parentDecl)) return false; + if(!isGlobalDecl(decl)) return false; // A global variable marked `static` indicates a traditional // global variable (albeit one that is implicitly local to @@ -733,6 +735,7 @@ namespace Slang // The coding of this loop is somewhat defensive to deal // with special cases that will be described along the way. // + auto outerScope = getScope(decl); for(;;) { // The first thing is to check what state the decl is @@ -757,6 +760,8 @@ namespace Slang // cannot affect the state in which the declaration is *checked*. // SemanticsContext subContext = baseContext ? SemanticsContext(*baseContext) : SemanticsContext(getShared()); + if (outerScope) + subContext = subContext.withOuterScope(outerScope); _dispatchDeclCheckingVisitor(decl, nextState, subContext); // In the common case, the visitor will have done the necessary @@ -1245,6 +1250,8 @@ namespace Slang } } } + + checkVisibility(varDecl); } void SemanticsDeclHeaderVisitor::visitStructDecl(StructDecl* structDecl) @@ -1261,11 +1268,12 @@ namespace Slang { addModifier(structDecl, m_astBuilder->create<NVAPIMagicModifier>()); } + checkVisibility(structDecl); } void SemanticsDeclHeaderVisitor::visitClassDecl(ClassDecl* classDecl) { - SLANG_UNUSED(classDecl); + checkVisibility(classDecl); } void SemanticsDeclBodyVisitor::checkVarDeclCommon(VarDeclBase* varDecl) @@ -1313,6 +1321,7 @@ namespace Slang OverloadResolveContext overloadContext; overloadContext.loc = varDecl->nameAndLoc.loc; overloadContext.mode = OverloadResolveContext::Mode::JustTrying; + overloadContext.sourceScope = m_outerScope; AddTypeOverloadCandidates(type, overloadContext); if(overloadContext.bestCandidates.getCount() != 0) @@ -1368,6 +1377,24 @@ namespace Slang } } + void addVisibilityModifier(ASTBuilder* builder, Decl* decl, DeclVisibility vis) + { + switch (vis) + { + case DeclVisibility::Public: + addModifier(decl, builder->create<PublicModifier>()); + break; + case DeclVisibility::Internal: + addModifier(decl, builder->create<InternalModifier>()); + break; + case DeclVisibility::Private: + addModifier(decl, builder->create<PrivateModifier>()); + break; + default: + break; + } + } + bool SemanticsVisitor::trySynthesizeDifferentialAssociatedTypeRequirementWitness( ConformanceCheckingContext* context, DeclRef<AssocTypeDecl> requirementDeclRef, @@ -1434,6 +1461,10 @@ namespace Slang diffField->checkState = DeclCheckState::SignatureChecked; diffField->parentDecl = aggTypeDecl; aggTypeDecl->members.add(diffField); + + auto visibility = getDeclVisibility(member); + addVisibilityModifier(m_astBuilder, diffField, visibility); + aggTypeDecl->invalidateMemberDictionary(); // Inject a `DerivativeMember` modifier on the differential field to point to itself. @@ -1539,6 +1570,15 @@ namespace Slang addModifier(aggTypeDecl, m_astBuilder->create<SynthesizedModifier>()); + // The visibility of synthesized decl should be the min of the parent decl and the requirement. + if (auto visModifier = requirementDeclRef.getDecl()->findModifier<VisibilityModifier>()) + { + auto requirementVisibility = getDeclVisibility(requirementDeclRef.getDecl()); + auto thisVisibility = getDeclVisibility(context->parentDecl); + auto visibility = Math::Min(thisVisibility, requirementVisibility); + addVisibilityModifier(m_astBuilder, aggTypeDecl, visibility); + } + // Synthesize the rest of IDifferential method conformances by recursively checking // conformance on the synthesized decl. checkAggTypeConformance(aggTypeDecl); @@ -1890,6 +1930,7 @@ namespace Slang DeclCheckState::ModifiersChecked, DeclCheckState::ReadyForReference, DeclCheckState::ReadyForLookup, + DeclCheckState::ReadyForConformances, DeclCheckState::Checked }; for(auto s : states) @@ -2810,6 +2851,7 @@ namespace Slang { synFuncDecl->nameAndLoc.name = getSession()->getNameObj("$__syn_" + synFuncDecl->nameAndLoc.name->text); } + // The result type of our synthesized method will be the expected // result type from the interface requirement. // @@ -2933,6 +2975,14 @@ namespace Slang auto attr = m_astBuilder->create<BackwardDifferentiableAttribute>(); addModifier(synFuncDecl, attr); } + // The visibility of synthesized decl should be the min of the parent decl and the requirement. + if (auto visModifier = requiredMemberDeclRef.getDecl()->findModifier<VisibilityModifier>()) + { + auto requirementVisibility = getDeclVisibility(requiredMemberDeclRef.getDecl()); + auto thisVisibility = getDeclVisibility(context->parentDecl); + auto visibility = Math::Min(thisVisibility, requirementVisibility); + addVisibilityModifier(m_astBuilder, synFuncDecl, visibility); + } } return synFuncDecl; @@ -3471,6 +3521,15 @@ namespace Slang synPropertyDecl->parentDecl = context->parentDecl; + // The visibility of synthesized decl should be the min of the parent decl and the requirement. + if (auto visModifier = requiredMemberDeclRef.getDecl()->findModifier<VisibilityModifier>()) + { + auto requirementVisibility = getDeclVisibility(requiredMemberDeclRef.getDecl()); + auto thisVisibility = getDeclVisibility(context->parentDecl); + auto visibility = Math::Min(thisVisibility, requirementVisibility); + addVisibilityModifier(m_astBuilder, synPropertyDecl, visibility); + } + // Once our synthesized declaration is complete, we need // to install it as the witness that satifies the given // requirement. @@ -3969,7 +4028,7 @@ namespace Slang // requests will be handled further down. For now we include // lookup results that might be usable, but not as-is. // - auto lookupResult = lookUpMember(m_astBuilder, this, name, subType, LookupMask::Default, LookupOptions::IgnoreBaseInterfaces); + auto lookupResult = lookUpMember(m_astBuilder, this, name, subType, nullptr, LookupMask::Default, LookupOptions::IgnoreBaseInterfaces); if(!lookupResult.isValid()) { @@ -4502,6 +4561,8 @@ namespace Slang void SemanticsDeclBasesVisitor::visitInterfaceDecl(InterfaceDecl* decl) { + SLANG_OUTER_SCOPE_CONTEXT_DECL_RAII(this, decl); + checkVisibility(decl); for( auto inheritanceDecl : decl->getMembersOfType<InheritanceDecl>() ) { ensureDecl(inheritanceDecl, DeclCheckState::CanUseBaseOfInheritanceDecl); @@ -4567,6 +4628,8 @@ namespace Slang // Furthermore, only the first inheritance clause (in source // order) is allowed to declare a base `struct` type. // + SLANG_OUTER_SCOPE_CONTEXT_DECL_RAII(this, decl); + Index inheritanceClauseCounter = 0; for( auto inheritanceDecl : decl->getMembersOfType<InheritanceDecl>() ) { @@ -4636,6 +4699,7 @@ namespace Slang // Furthermore, only the first inheritance clause (in source // order) is allowed to declare a base `class` type. // + SLANG_OUTER_SCOPE_CONTEXT_DECL_RAII(this, decl); Index inheritanceClauseCounter = 0; for (auto inheritanceDecl : decl->getMembersOfType<InheritanceDecl>()) { @@ -4768,6 +4832,9 @@ namespace Slang void SemanticsDeclBasesVisitor::visitEnumDecl(EnumDecl* decl) { + SLANG_OUTER_SCOPE_CONTEXT_DECL_RAII(this, decl); + checkVisibility(decl); + // An `enum` type can inherit from interfaces, and also // from a single "tag" type that must: // @@ -4775,7 +4842,6 @@ namespace Slang // * come first in the list of base types // Index inheritanceClauseCounter = 0; - Type* tagType = nullptr; InheritanceDecl* tagTypeInheritanceDecl = nullptr; for(auto inheritanceDecl : decl->getMembersOfType<InheritanceDecl>()) @@ -4938,6 +5004,8 @@ namespace Slang void SemanticsDeclBodyVisitor::visitEnumDecl(EnumDecl* decl) { + SLANG_OUTER_SCOPE_CONTEXT_DECL_RAII(this, decl); + auto enumType = DeclRefType::create(m_astBuilder, makeDeclRef(decl)); auto tagType = decl->tagType; @@ -5063,6 +5131,7 @@ namespace Slang void SemanticsDeclHeaderVisitor::visitTypeDefDecl(TypeDefDecl* decl) { decl->type = CheckProperType(decl->type); + checkVisibility(decl); } void SemanticsDeclHeaderVisitor::visitGlobalGenericParamDecl(GlobalGenericParamDecl* decl) @@ -5079,6 +5148,7 @@ namespace Slang auto interfaceDecl = as<InterfaceDecl>(decl->parentDecl); if (!interfaceDecl) getSink()->diagnose(decl, Slang::Diagnostics::assocTypeInInterfaceOnly); + checkVisibility(decl); } void SemanticsDeclBodyVisitor::visitFunctionDeclBase(FunctionDeclBase* decl) @@ -6154,6 +6224,7 @@ namespace Slang } } } + checkVisibility(decl); } void SemanticsDeclHeaderVisitor::visitFuncDecl(FuncDecl* funcDecl) @@ -6464,6 +6535,7 @@ namespace Slang { decl->type = CheckUsableType(decl->type); visitAbstractStorageDeclCommon(decl); + checkVisibility(decl); } Type* SemanticsDeclHeaderVisitor::_getAccessorStorageType(AccessorDecl* decl) @@ -6768,13 +6840,19 @@ namespace Slang importedModulesList.add(moduleDecl); importedModulesSet.add(moduleDecl); - // Create a new sub-scope to wire the module + // Create a new sub-scope to wire the module's scope and its nested FileDecl's scopes // into our lookup chain. - auto subScope = getASTBuilder()->create<Scope>(); - subScope->containerDecl = moduleDecl; + for (auto moduleScope = moduleDecl->ownedScope; moduleScope; moduleScope = moduleScope->nextSibling) + { + if (moduleScope->containerDecl != moduleDecl && moduleScope->containerDecl->parentDecl != moduleDecl) + continue; - subScope->nextSibling = scope->nextSibling; - scope->nextSibling = subScope; + auto subScope = getASTBuilder()->create<Scope>(); + subScope->containerDecl = moduleScope->containerDecl; + + subScope->nextSibling = scope->nextSibling; + scope->nextSibling = subScope; + } // Also import any modules from nested `import` declarations // with the `__exported` modifier diff --git a/source/slang/slang-check-expr.cpp b/source/slang/slang-check-expr.cpp index 7edf27b30..dd868f70c 100644 --- a/source/slang/slang-check-expr.cpp +++ b/source/slang/slang-check-expr.cpp @@ -225,6 +225,20 @@ namespace Slang return expr; } + Scope* SemanticsVisitor::getScope(SyntaxNode* node) + { + while (auto declBase = as<Decl>(node)) + { + if (auto container = as<ContainerDecl>(node)) + { + if (container->ownedScope) + return container->ownedScope; + } + node = declBase->parentDecl; + } + return nullptr; + } + static SourceLoc _getMemberOpLoc(Expr* expr) { if (auto m = as<MemberExpr>(expr)) @@ -794,6 +808,121 @@ namespace Slang } } + DeclVisibility SemanticsVisitor::getDeclVisibility(Decl* decl) + { + if (as<GenericTypeParamDecl>(decl) || as<GenericValueParamDecl>(decl) || as<GenericTypeConstraintDecl>(decl)) + { + auto genericDecl = as<GenericDecl>(decl->parentDecl); + if (!genericDecl) + return DeclVisibility::Default; + if (genericDecl->inner) + return getDeclVisibility(genericDecl->inner); + return DeclVisibility::Default; + } + if (auto genericDecl = as<GenericDecl>(decl)) + decl = genericDecl->inner; + for (; decl; decl = getParentDecl(decl)) + { + if (as<AccessorDecl>(decl)) + continue; + if (as<EnumCaseDecl>(decl)) + continue; + break; + } + if (!decl) + return DeclVisibility::Public; + + for (auto modifier : decl->modifiers) + { + if (as<PublicModifier>(modifier)) + return DeclVisibility::Public; + else if (as<InternalModifier>(modifier)) + return DeclVisibility::Internal; + else if (as<PrivateModifier>(modifier)) + return DeclVisibility::Private; + } + + if (auto parentModule = getModuleDecl(decl)) + return parentModule->isInLegacyLanguage ? DeclVisibility::Public : DeclVisibility::Internal; + + return DeclVisibility::Default; + } + + DeclVisibility SemanticsVisitor::getTypeVisibility(Type* type) + { + if (auto declRefType = as<DeclRefType>(type)) + { + auto v = getDeclVisibility(declRefType->getDeclRef().getDecl()); + auto args = findInnerMostGenericArgs(SubstitutionSet(declRefType->getDeclRef())); + for (auto arg : args) + { + if (auto typeArg = as<DeclRefType>(arg)) + v = Math::Min(v, getTypeVisibility(typeArg)); + } + return v; + } + return DeclVisibility::Public; + } + + bool SemanticsVisitor::isDeclVisibleFromScope(DeclRef<Decl> declRef, Scope* scope) + { + auto visibility = getDeclVisibility(declRef.getDecl()); + if (visibility == DeclVisibility::Public) + return true; + if (visibility == DeclVisibility::Internal) + { + // Check that the decl is in the same module as the scope. + auto declModule = getModuleDecl(declRef.getDecl()); + if (declModule == getModuleDecl(scope)) + return true; + } + if (visibility == DeclVisibility::Private) + { + // Check that the decl is in the same or parent container decl as scope. + Decl* parentContainer = declRef.getDecl(); + for (;parentContainer; parentContainer = parentContainer->parentDecl) + { + if (as<AggTypeDeclBase>(parentContainer)) + break; + if (as<NamespaceDeclBase>(parentContainer)) + break; + } + + for (auto s = scope; s; s = s->parent) + { + if (s->containerDecl == parentContainer) + return true; + } + return false; + } + return false; + } + + LookupResult SemanticsVisitor::filterLookupResultByVisibility(const LookupResult& lookupResult) + { + if (!m_outerScope) + return lookupResult; + LookupResult filteredResult; + for (auto item : lookupResult) + { + if (isDeclVisibleFromScope(item.declRef, m_outerScope)) + AddToLookupResult(filteredResult, item); + } + return filteredResult; + } + + LookupResult SemanticsVisitor::filterLookupResultByVisibilityAndDiagnose(const LookupResult& lookupResult, SourceLoc loc, bool& outDiagnosed) + { + outDiagnosed = false; + auto result = filterLookupResultByVisibility(lookupResult); + if (lookupResult.isValid() && !result.isValid()) + { + getSink()->diagnose(loc, Diagnostics::declIsNotVisible, lookupResult.item.declRef); + outDiagnosed = true; + } + return result; + } + LookupResult SemanticsVisitor::resolveOverloadedLookup(LookupResult const& inResult) { // If the result isn't actually overloaded, it is fine as-is @@ -987,6 +1116,7 @@ namespace Slang this, getName("Differential"), type, + nullptr, Slang::LookupMask::type, Slang::LookupOptions::None); @@ -1141,7 +1271,7 @@ namespace Slang // a scope in place. If we do, we will re-use it for any sub-expressions. // If not, we need to create one. // - if(getExprLocalScope()) + if (getExprLocalScope()) { return dispatchExpr(term, *this); } @@ -1860,11 +1990,15 @@ namespace Slang this, operatorName, baseType, + m_outerScope, LookupMask::Default, LookupOptions::NoDeref); + bool diagnosed = false; + lookupResult = filterLookupResultByVisibilityAndDiagnose(lookupResult, subscriptExpr->loc, diagnosed); if (!lookupResult.isValid()) { - getSink()->diagnose(subscriptExpr, Diagnostics::subscriptNonArray, baseType); + if (!diagnosed) + getSink()->diagnose(subscriptExpr, Diagnostics::subscriptNonArray, baseType); return CreateErrorExpr(subscriptExpr); } auto subscriptFuncExpr = createLookupResultExpr( @@ -2333,6 +2467,9 @@ namespace Slang auto lookupResult = lookUp( m_astBuilder, this, expr->name, expr->scope); + + bool diagnosed = false; + lookupResult = filterLookupResultByVisibilityAndDiagnose(lookupResult, expr->loc, diagnosed); if (expr->name == getSession()->getCompletionRequestTokenName()) { @@ -2353,7 +2490,8 @@ namespace Slang expr); } - getSink()->diagnose(expr, Diagnostics::undefinedIdentifier2, expr->name); + if (!diagnosed) + getSink()->diagnose(expr, Diagnostics::undefinedIdentifier2, expr->name); return expr; } @@ -3387,161 +3525,183 @@ namespace Slang Expr* SemanticsVisitor::_lookupStaticMember(DeclRefExpr* expr, Expr* baseExpression) { - auto& baseType = baseExpression->type; + LookupResult globalLookupResult; + bool hasErrors = false; + Expr* base = nullptr; + auto handleLeafCase = [&](DeclRef<Decl> baseDeclRef, Type* type) + { + auto aggTypeDeclRef = as<AggTypeDeclBase>(baseDeclRef); - // TODO: Need to handle overloaded case (in case we - // have multiple visible types and/or namespaces - // with the same name). + if (auto namespaceDeclRef = as<NamespaceDeclBase>(baseDeclRef)) + { + // We are looking up a namespace member. + // + // This ought to be the easy case, because + // there are no restrictions on whether + // we can reference the declaration here. + // + LookupResult nsLookupResult = lookUpDirectAndTransparentMembers( + m_astBuilder, + this, + expr->name, + namespaceDeclRef.getDecl(), + namespaceDeclRef); + AddToLookupResult(globalLookupResult, nsLookupResult); - if (auto namespaceType = as<NamespaceType>(baseType)) - { - // We are looking up a namespace member. - // - auto namespaceDeclRef = namespaceType->getDeclRef(); + } + else if (aggTypeDeclRef || type) + { + // We are looking up a member inside a type. + // We want to be careful here because we should only find members + // that are implicitly or explicitly `static`. + // + if (type == nullptr) + type = DeclRefType::create(m_astBuilder, aggTypeDeclRef); - // This ought to be the easy case, because - // there are no restrictions on whether - // we can reference the declaration here. - // - LookupResult lookupResult = lookUpDirectAndTransparentMembers( - m_astBuilder, - this, - expr->name, - namespaceDeclRef.getDecl(), - namespaceDeclRef); - if (!lookupResult.isValid()) - { - return lookupMemberResultFailure(expr, baseType); - } + if (as<ErrorType>(type)) + { + return; + } - if (expr->name == getSession()->getCompletionRequestTokenName()) - { - suggestCompletionItems(CompletionSuggestions::ScopeKind::Member, lookupResult); - } - return createLookupResultExpr( - expr->name, - lookupResult, - nullptr, - expr->loc, - expr); - } - else if (auto typeType = as<TypeType>(baseType)) - { - // We are looking up a member inside a type. - // We want to be careful here because we should only find members - // that are implicitly or explicitly `static`. - // - // TODO: this duplicates a *lot* of logic with the case below. - // We need to fix that. - auto type = typeType->getType(); + LookupResult lookupResult = lookUpMember( + m_astBuilder, + this, + expr->name, + type, + m_outerScope); - if (as<ErrorType>(type)) - { - return CreateErrorExpr(expr); - } + // We need to confirm that whatever member we + // are trying to refer to is usable via static reference. + // + // TODO: eventually we might allow a non-static + // member to be adapted by turning it into something + // like a closure that takes the missing `this` parameter. + // + // E.g., a static reference to a method could be treated + // as a value with a function type, where the first parameter + // is `type`. + // + // The biggest challenge there is that we'd need to arrange + // to generate "dispatcher" functions that could be used + // to implement that function, in the case where we are + // making a static reference to some kind of polymorphic declaration. + // + // (Also, static references to fields/properties would get even + // harder, because you'd have to know whether a getter/setter/ref-er + // is needed). + // + // For now let's just be expedient and disallow all of that, because + // we can always add it back in later. - LookupResult lookupResult = lookUpMember( - m_astBuilder, - this, - expr->name, - type); - if (!lookupResult.isValid()) - { - return lookupMemberResultFailure(expr, baseType); - } + // If the lookup result is valid, then we want to filter + // it to just those candidates that can be referenced statically, + // and ignore any that would only be allowed as instance members. + // + if (lookupResult.isValid()) + { + // We track both the usable items, and whether or + // not there were any non-static items that need + // to be ignored. + // + bool anyNonStatic = false; + List<LookupResultItem> staticItems; + for (auto item : lookupResult) + { + // Is this item usable as a static member? + if (isUsableAsStaticMember(item)) + { + // If yes, then it will be part of the output. + staticItems.add(item); + } + else + { + // If no, then we might need to output an error. + anyNonStatic = true; + } + } - // We need to confirm that whatever member we - // are trying to refer to is usable via static reference. - // - // TODO: eventually we might allow a non-static - // member to be adapted by turning it into something - // like a closure that takes the missing `this` parameter. - // - // E.g., a static reference to a method could be treated - // as a value with a function type, where the first parameter - // is `type`. - // - // The biggest challenge there is that we'd need to arrange - // to generate "dispatcher" functions that could be used - // to implement that function, in the case where we are - // making a static reference to some kind of polymorphic declaration. - // - // (Also, static references to fields/properties would get even - // harder, because you'd have to know whether a getter/setter/ref-er - // is needed). - // - // For now let's just be expedient and disallow all of that, because - // we can always add it back in later. + // Was there anything non-static in the list? + if (anyNonStatic) + { + // If we had some static items, then that's okay, + // we just want to use our newly-filtered list. + if (staticItems.getCount()) + { + lookupResult.items = staticItems; + lookupResult.item = staticItems[0]; + } + else + { + // Otherwise, it is time to report an error. + getSink()->diagnose( + expr->loc, + Diagnostics::staticRefToNonStaticMember, + type, + expr->name); + hasErrors = true; + return; + } + } + // If there were no non-static items, then the `items` + // array already represents what we'd get by filtering... - // If the lookup result is valid, then we want to filter - // it to just those candidates that can be referenced statically, - // and ignore any that would only be allowed as instance members. - // - if(lookupResult.isValid()) - { - // We track both the usable items, and whether or - // not there were any non-static items that need - // to be ignored. - // - bool anyNonStatic = false; - List<LookupResultItem> staticItems; - for (auto item : lookupResult) - { - // Is this item usable as a static member? - if (isUsableAsStaticMember(item)) - { - // If yes, then it will be part of the output. - staticItems.add(item); - } - else - { - // If no, then we might need to output an error. - anyNonStatic = true; + AddToLookupResult(globalLookupResult, lookupResult); + base = baseExpression; } } + }; - // Was there anything non-static in the list? - if (anyNonStatic) - { - // If we had some static items, then that's okay, - // we just want to use our newly-filtered list. - if (staticItems.getCount()) - { - lookupResult.items = staticItems; - lookupResult.item = staticItems[0]; - } - else - { - // Otherwise, it is time to report an error. - getSink()->diagnose( - expr->loc, - Diagnostics::staticRefToNonStaticMember, - type, - expr->name); - return CreateErrorExpr(expr); - } - } - // If there were no non-static items, then the `items` - // array already represents what we'd get by filtering... - } - if (expr->name == getSession()->getCompletionRequestTokenName()) + auto handleLeafExpr = [&](Expr* e) { - suggestCompletionItems(CompletionSuggestions::ScopeKind::Member, lookupResult); + if (auto nsType = as<NamespaceType>(e->type)) + handleLeafCase(nsType->getDeclRef(), nsType); + else if (auto aggType = as<DeclRefType>(e->type)) + handleLeafCase(aggType->getDeclRef(), aggType); + else if (auto typetype = as<TypeType>(e->type)) + handleLeafCase(DeclRef<Decl>(), typetype->getType()); + }; + + auto& baseType = baseExpression->type; + if (as<ErrorType>(baseType)) + { + return CreateErrorExpr(expr); + } + + if (auto overloaded = as<OverloadedExpr>(baseExpression)) + { + for (auto candidate : overloaded->lookupResult2.items) + handleLeafCase(candidate.declRef, nullptr); + } + else if (auto overloaded2 = as<OverloadedExpr2>(baseExpression)) + { + for (auto candidate : overloaded2->candidiateExprs) + { + handleLeafExpr(candidate); } - return createLookupResultExpr( - expr->name, - lookupResult, - baseExpression, - expr->loc, - expr); } - else if (as<ErrorType>(baseType)) + else { - return CreateErrorExpr(expr); + handleLeafExpr(baseExpression); + } + + bool diagnosed = false; + globalLookupResult = filterLookupResultByVisibilityAndDiagnose(globalLookupResult, expr->loc, diagnosed); + diagnosed |= hasErrors; + if (!globalLookupResult.isValid()) + { + return lookupMemberResultFailure(expr, baseType, diagnosed); } - // Failure - return lookupMemberResultFailure(expr, baseType); + if (expr->name == getSession()->getCompletionRequestTokenName()) + { + suggestCompletionItems(CompletionSuggestions::ScopeKind::Member, globalLookupResult); + } + return createLookupResultExpr( + expr->name, + globalLookupResult, + base, + expr->loc, + expr); } Expr* SemanticsExprVisitor::visitStaticMemberExpr(StaticMemberExpr* expr) @@ -3565,12 +3725,14 @@ namespace Slang Expr* SemanticsVisitor::lookupMemberResultFailure( DeclRefExpr* expr, - QualType const& baseType) + QualType const& baseType, + bool supressDiagnostic) { // Check it's a member expression SLANG_ASSERT(as<StaticMemberExpr>(expr) || as<MemberExpr>(expr)); - getSink()->diagnose(expr, Diagnostics::noMemberOfNameInType, expr->name, baseType); + if (!supressDiagnostic) + getSink()->diagnose(expr, Diagnostics::noMemberOfNameInType, expr->name, baseType); expr->type = QualType(m_astBuilder->getErrorType()); return expr; } @@ -3678,6 +3840,14 @@ namespace Slang { return _lookupStaticMember(expr, expr->baseExpression); } + else if (as<OverloadedExpr>(expr->baseExpression)) + { + return _lookupStaticMember(expr, expr->baseExpression); + } + else if (as<OverloadedExpr2>(expr->baseExpression)) + { + return _lookupStaticMember(expr, expr->baseExpression); + } else if (as<ErrorType>(baseType)) { return CreateErrorExpr(expr); @@ -3688,10 +3858,13 @@ namespace Slang m_astBuilder, this, expr->name, - baseType.Ptr()); + baseType.Ptr(), + m_outerScope); + bool diagnosed = false; + lookupResult = filterLookupResultByVisibilityAndDiagnose(lookupResult, expr->loc, diagnosed); if (!lookupResult.isValid()) { - return lookupMemberResultFailure(expr, baseType); + return lookupMemberResultFailure(expr, baseType, diagnosed); } if (expr->name == getSession()->getCompletionRequestTokenName()) { diff --git a/source/slang/slang-check-impl.h b/source/slang/slang-check-impl.h index e9654830a..43844cf70 100644 --- a/source/slang/slang-check-impl.h +++ b/source/slang/slang-check-impl.h @@ -217,6 +217,7 @@ namespace Slang FixityChecked, TypeChecked, DirectionChecked, + VisibilityChecked, Applicable, }; Status status = Status::Unchecked; @@ -773,6 +774,8 @@ namespace Slang struct SemanticsContext { public: + friend struct OuterScopeContextRAII; + explicit SemanticsContext( SharedSemanticsContext* shared) : m_shared(shared) @@ -804,6 +807,8 @@ namespace Slang result.m_parentFunc = parentFunc; result.m_outerStmts = nullptr; result.m_parentDifferentiableAttr = parentFunc->findModifier<DifferentiableAttribute>(); + if (parentFunc->ownedScope) + result.m_outerScope = parentFunc->ownedScope; return result; } @@ -868,6 +873,7 @@ namespace Slang }; ExprLocalScope* getExprLocalScope() { return m_exprLocalScope; } + Scope* getOuterScope() { return m_outerScope; } SemanticsContext withExprLocalScope(ExprLocalScope* exprLocalScope) { @@ -876,6 +882,13 @@ namespace Slang return result; } + SemanticsContext withOuterScope(Scope* scope) + { + SemanticsContext result(*this); + result.m_outerScope = scope; + return result; + } + SemanticsContext withTreatAsDifferentiable(TreatAsDifferentiableExpr* expr) { SemanticsContext result(*this); @@ -921,8 +934,31 @@ namespace Slang TreatAsDifferentiableExpr* m_treatAsDifferentiableExpr = nullptr; ASTBuilder* m_astBuilder = nullptr; + + Scope* m_outerScope = nullptr; + }; + + struct OuterScopeContextRAII + { + SemanticsContext* m_context; + Scope* m_oldOuterScope; + + OuterScopeContextRAII(SemanticsContext* context, Scope* outerScope) + : m_context(context) + , m_oldOuterScope(context->getOuterScope()) + { + context->m_outerScope = outerScope; + } + + ~OuterScopeContextRAII() + { + m_context->m_outerScope = m_oldOuterScope; + } }; +#define SLANG_OUTER_SCOPE_CONTEXT_RAII(context, scope) OuterScopeContextRAII _outerScopeContextRAII(context, scope) +#define SLANG_OUTER_SCOPE_CONTEXT_DECL_RAII(context, decl) OuterScopeContextRAII _outerScopeContextRAII(context, decl->ownedScope?decl->ownedScope:context->getOuterScope()) + struct SemanticsVisitor : public SemanticsContext { typedef SemanticsContext Super; @@ -1010,6 +1046,8 @@ namespace Slang /// If `expr` has Ref<T> Type, convert it into an l-value expr that has T type. Expr* maybeOpenRef(Expr* expr); + Scope* getScope(SyntaxNode* node); + void diagnoseDeprecatedDeclRefUsage(DeclRef<Decl> declRef, SourceLoc loc, Expr* originalExpr); DeclRef<Decl> getDefaultDeclRef(Decl* decl) @@ -1056,6 +1094,11 @@ namespace Slang SourceLoc loc, Expr* originalExpr); + DeclVisibility getDeclVisibility(Decl* decl); + DeclVisibility getTypeVisibility(Type* type); + bool isDeclVisibleFromScope(DeclRef<Decl> declRef, Scope* scope); + LookupResult filterLookupResultByVisibility(const LookupResult& lookupResult); + LookupResult filterLookupResultByVisibilityAndDiagnose(const LookupResult& lookupResult, SourceLoc loc, bool& outDiagnosed); Val* resolveVal(Val* val) { @@ -1444,6 +1487,7 @@ namespace Slang ModifiableSyntaxNode* syntaxNode); void checkModifiers(ModifiableSyntaxNode* syntaxNode); + void checkVisibility(Decl* decl); bool doesSignatureMatchRequirement( DeclRef<CallableDecl> satisfyingMemberDeclRef, @@ -1985,6 +2029,9 @@ namespace Slang // Source location of the "function" part of the expression, if any SourceLoc funcLoc; + // The source scope of the lookup for performing visibiliity tests. + Scope* sourceScope = nullptr; + // The original arguments to the call Index argCount = 0; Expr** args = nullptr; @@ -2048,6 +2095,10 @@ namespace Slang OverloadResolveContext& context, OverloadCandidate const& candidate); + bool TryCheckOverloadCandidateVisibility( + OverloadResolveContext& context, + OverloadCandidate const& candidate); + bool TryCheckGenericOverloadCandidateTypes( OverloadResolveContext& context, OverloadCandidate& candidate); @@ -2371,7 +2422,8 @@ namespace Slang Expr* lookupMemberResultFailure( DeclRefExpr* expr, - QualType const& baseType); + QualType const& baseType, + bool supressDiagnostic = false); SharedSemanticsContext& operator=(const SharedSemanticsContext &) = delete; diff --git a/source/slang/slang-check-modifier.cpp b/source/slang/slang-check-modifier.cpp index 569804ff4..339ecba4c 100644 --- a/source/slang/slang-check-modifier.cpp +++ b/source/slang/slang-check-modifier.cpp @@ -950,7 +950,7 @@ namespace Slang { if (auto parentExtension = as<ExtensionDecl>(varDecl->parentDecl)) { - auto originalMemberLookup = lookUpMember(m_astBuilder, this, varDecl->getName(), parentExtension->targetType); + auto originalMemberLookup = lookUpMember(m_astBuilder, this, varDecl->getName(), parentExtension->targetType, parentExtension->ownedScope); LookupResult filteredResult; for (auto item : originalMemberLookup.items) { @@ -1042,6 +1042,23 @@ namespace Slang } } + if (as<PrivateModifier>(m)) + { + if (as<AggTypeDeclBase>(syntaxNode) || as<NamespaceDeclBase>(syntaxNode)) + { + getSink()->diagnose(m, Diagnostics::invalidUseOfPrivateVisibility, as<Decl>(syntaxNode)); + } + else if (auto decl = as<Decl>(syntaxNode)) + { + // Interface requirements can't be private. + if (isInterfaceRequirement(decl)) + { + getSink()->diagnose(m, Diagnostics::invalidUseOfPrivateVisibility, as<Decl>(syntaxNode)); + } + } + } + + // Default behavior is to leave things as they are, // and assume that modifiers are mostly already checked. // @@ -1054,6 +1071,71 @@ namespace Slang return m; } + void SemanticsVisitor::checkVisibility(Decl* decl) + { + if (as<AccessorDecl>(decl)) + { + return; + } + ShortList<Type*> typesToVerify; + if (auto varDecl = as<VarDeclBase>(decl)) + { + typesToVerify.add(varDecl->type); + } + else if (auto callable = as<CallableDecl>(decl)) + { + typesToVerify.add(callable->returnType); + typesToVerify.add(callable->errorType); + for (auto param : callable->getParameters()) + { + typesToVerify.add(param->type); + } + } + else if (auto propertyDecl = as<PropertyDecl>(decl)) + { + typesToVerify.add(propertyDecl->type); + } + else if (as<AggTypeDeclBase>(decl)) + { + } + else if (auto typeDecl = as<TypeDefDecl>(decl)) + { + typesToVerify.add(typeDecl->type); + } + else + { + return; + } + auto thisVisibility = getDeclVisibility(decl); + + // First, we check that the decl's type does not have lower visibility. + for (auto type : typesToVerify) + { + if (!type) + continue; + DeclVisibility typeVisibility = getTypeVisibility(type); + if (typeVisibility < thisVisibility) + { + getSink()->diagnose(decl, Diagnostics::useOfLessVisibleType, decl, type); + break; + } + } + + // Next, we check that the decl does not have higher visiblity than its parent. + Decl* parentDecl = decl; + for (; parentDecl; parentDecl = parentDecl->parentDecl) + { + if (as<AggTypeDeclBase>(parentDecl)) + break; + } + if (!parentDecl) + return; + auto parentVisibility = getDeclVisibility(parentDecl); + if (thisVisibility > parentVisibility) + { + getSink()->diagnose(decl, Diagnostics::declCannotHaveHigherVisibility, decl, parentDecl); + } + } void SemanticsVisitor::checkModifiers(ModifiableSyntaxNode* syntaxNode) { diff --git a/source/slang/slang-check-overload.cpp b/source/slang/slang-check-overload.cpp index d7d29a4e1..2912a79b0 100644 --- a/source/slang/slang-check-overload.cpp +++ b/source/slang/slang-check-overload.cpp @@ -190,6 +190,33 @@ namespace Slang } } + bool SemanticsVisitor::TryCheckOverloadCandidateVisibility(OverloadResolveContext& context, OverloadCandidate const& candidate) + { + // Always succeeds when we are trying out constructors. + if (context.mode == OverloadResolveContext::Mode::JustTrying) + { + if (as<ConstructorDecl>(candidate.item.declRef)) + return true; + } + + if (!context.sourceScope) + return true; + + if (!candidate.item.declRef) + return true; + + if (!isDeclVisibleFromScope(candidate.item.declRef, context.sourceScope)) + { + if (context.mode == OverloadResolveContext::Mode::ForReal) + { + getSink()->diagnose(context.loc, Diagnostics::declIsNotVisible, candidate.item.declRef); + } + return false; + } + + return true; + } + bool SemanticsVisitor::TryCheckGenericOverloadCandidateTypes( OverloadResolveContext& context, OverloadCandidate& candidate) @@ -704,6 +731,10 @@ namespace Slang if (!TryCheckOverloadCandidateConstraints(context, candidate)) return; + candidate.status = OverloadCandidate::Status::VisibilityChecked; + if (!TryCheckOverloadCandidateVisibility(context, candidate)) + return; + candidate.status = OverloadCandidate::Status::Applicable; } @@ -777,6 +808,9 @@ namespace Slang if (!TryCheckOverloadCandidateConstraints(context, candidate)) goto error; + if (!TryCheckOverloadCandidateVisibility(context, candidate)) + goto error; + { Expr* baseExpr; switch(candidate.flavor) @@ -887,7 +921,6 @@ namespace Slang } else { - SLANG_DIAGNOSE_UNEXPECTED(getSink(), context.loc, "no original expression for overload result"); return nullptr; } } @@ -1511,6 +1544,7 @@ namespace Slang this, getName("$init"), type, + context.sourceScope, LookupMask::Default, LookupOptions::NoDeref); @@ -1885,7 +1919,7 @@ namespace Slang context.argCount = expr->arguments.getCount(); context.args = expr->arguments.getBuffer(); context.loc = expr->loc; - + context.sourceScope = m_outerScope; context.baseExpr = GetBaseExpr(funcExpr); // TODO: We should have a special case here where an `InvokeExpr` @@ -1975,26 +2009,16 @@ namespace Slang Index candidateCount = context.bestCandidates.getCount(); Index maxCandidatesToPrint = 10; // don't show too many candidates at once... Index candidateIndex = 0; + context.bestCandidates.sort([](const OverloadCandidate& c1, const OverloadCandidate& c2) { return c1.status < c2.status; }); + for (auto candidate : context.bestCandidates) { String declString = ASTPrinter::getDeclSignatureString(candidate.item, m_astBuilder); -// declString = declString + "[" + String(candidate.conversionCostSum) + "]"; - -#if 0 - // Debugging: ensure that we don't consider multiple declarations of the same operation - if (auto decl = as<CallableDecl>(candidate.item.declRef.decl)) - { - char buffer[1024]; - sprintf_s(buffer, sizeof(buffer), "[this:%p, primary:%p, next:%p]", - decl, - decl->primaryDecl, - decl->nextDecl); - declString.append(buffer); - } -#endif - - getSink()->diagnose(candidate.item.declRef, Diagnostics::overloadCandidate, declString); + if (candidate.status == OverloadCandidate::Status::VisibilityChecked) + getSink()->diagnose(candidate.item.declRef, Diagnostics::invisibleOverloadCandidate, declString); + else + getSink()->diagnose(candidate.item.declRef, Diagnostics::overloadCandidate, declString); candidateIndex++; if (candidateIndex == maxCandidatesToPrint) @@ -2126,7 +2150,7 @@ namespace Slang context.argCount = args.getCount(); context.args = args.getBuffer(); context.loc = genericAppExpr->loc; - + context.sourceScope = m_outerScope; context.baseExpr = GetBaseExpr(baseExpr); AddGenericOverloadCandidates(baseExpr, context); diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h index 8eb0584d0..c95d5ea98 100644 --- a/source/slang/slang-diagnostic-defs.h +++ b/source/slang/slang-diagnostic-defs.h @@ -357,6 +357,13 @@ DIAGNOSTIC(30503, Error, primaryModuleFileCannotStartWithImplementingDecl, "a pr DIAGNOSTIC(30504, Warning, primaryModuleFileMustStartWithModuleDecl, "a primary source file for a module should start with 'module'.") DIAGNOSTIC(30505, Error, implementingMustReferencePrimaryModuleFile, "the source file referenced by 'implementing' must be a primary module file starting with a 'module' declaration.") +// Visibilty +DIAGNOSTIC(30600, Error, declIsNotVisible, "'$0' is not accessible from the current context.") +DIAGNOSTIC(30601, Error, declCannotHaveHigherVisibility, "'$0' cannot have a higher visibility than '$1'.") +DIAGNOSTIC(30602, Error, declCannotHaveLowerVisibility, "'$0' cannot have a lower visibility than '$1'.") +DIAGNOSTIC(30603, Error, invalidUseOfPrivateVisibility, "'$0' cannot have private visibility.") +DIAGNOSTIC(30604, Error, useOfLessVisibleType, "'$0' references less visible type '$1'.") + // Attributes DIAGNOSTIC(31000, Error, unknownAttributeName, "unknown attribute '$0'") DIAGNOSTIC(31001, Error, attributeArgumentCountMismatch, "attribute '$0' expects $1 arguments ($2 provided)") @@ -502,6 +509,8 @@ DIAGNOSTIC(39999, Error, ambiguousOverloadForNameWithArgs, "ambiguous call to '$ DIAGNOSTIC(39999, Error, ambiguousOverloadWithArgs, "ambiguous call to overloaded operation with arguments of type $0") DIAGNOSTIC(39999, Note, overloadCandidate, "candidate: $0") +DIAGNOSTIC(39999, Note, invisibleOverloadCandidate, "candidate (invisible): $0") + DIAGNOSTIC(39999, Note, moreOverloadCandidates, "$0 more overload candidates") DIAGNOSTIC(39999, Error, caseOutsideSwitch, "'case' not allowed outside of a 'switch' statement") diff --git a/source/slang/slang-emit-c-like.cpp b/source/slang/slang-emit-c-like.cpp index d0efce0f5..7f7e23a1c 100644 --- a/source/slang/slang-emit-c-like.cpp +++ b/source/slang/slang-emit-c-like.cpp @@ -4122,8 +4122,8 @@ void CLikeSourceEmitter::computeEmitActions(IRModule* module, List<EmitAction>& { if( as<IRType>(inst) ) { - // Don't emit a type unless it is actually used or is marked public. - if (!inst->findDecoration<IRPublicDecoration>()) + // Don't emit a type unless it is actually used or is marked exported. + if (!inst->findDecoration<IRHLSLExportDecoration>()) continue; } diff --git a/source/slang/slang-ir-autodiff.cpp b/source/slang/slang-ir-autodiff.cpp index e4f3f3f94..9166c560a 100644 --- a/source/slang/slang-ir-autodiff.cpp +++ b/source/slang/slang-ir-autodiff.cpp @@ -2066,20 +2066,15 @@ void releaseNullDifferentialType(AutoDiffSharedContext* context) { if (auto nullStruct = context->nullDifferentialStructType) { - if (auto publicDecoration = nullStruct->findDecoration<IRPublicDecoration>()) - publicDecoration->removeAndDeallocate(); if (auto keepAliveDecoration = nullStruct->findDecoration<IRKeepAliveDecoration>()) keepAliveDecoration->removeAndDeallocate(); } if (auto nullWitness = context->nullDifferentialWitness) { - if (auto publicDecoration = nullWitness->findDecoration<IRPublicDecoration>()) - publicDecoration->removeAndDeallocate(); if (auto keepAliveDecoration = nullWitness->findDecoration<IRKeepAliveDecoration>()) keepAliveDecoration->removeAndDeallocate(); } - } bool finalizeAutoDiffPass(IRModule* module) diff --git a/source/slang/slang-ir-dll-export.cpp b/source/slang/slang-ir-dll-export.cpp index d7a18e665..af5f70eb3 100644 --- a/source/slang/slang-ir-dll-export.cpp +++ b/source/slang/slang-ir-dll-export.cpp @@ -4,6 +4,7 @@ #include "slang-ir.h" #include "slang-ir-insts.h" #include "slang-ir-marshal-native-call.h" +#include "slang-ir-util.h" namespace Slang { @@ -26,10 +27,7 @@ struct DllExportContext builder.addPublicDecoration(wrapper); builder.addKeepAliveDecoration(wrapper); builder.addHLSLExportDecoration(wrapper); - if (auto oldPublicDecoration = func->findDecoration<IRPublicDecoration>()) - { - oldPublicDecoration->removeFromParent(); - } + removeLinkageDecorations(func); } void processModule() diff --git a/source/slang/slang-ir-generics-lowering-context.cpp b/source/slang/slang-ir-generics-lowering-context.cpp index 325568040..212e16483 100644 --- a/source/slang/slang-ir-generics-lowering-context.cpp +++ b/source/slang/slang-ir-generics-lowering-context.cpp @@ -60,7 +60,7 @@ namespace Slang return result; IRBuilder builderStorage(module); auto builder = &builderStorage; - builder->setInsertBefore(typeInst->next); + builder->setInsertAfter(typeInst); result = builder->emitMakeRTTIObject(typeInst); @@ -75,10 +75,11 @@ namespace Slang String rttiObjName = exportDecoration->getMangledName(); builder->addExportDecoration(result, rttiObjName.getUnownedSlice()); } - // Make sure the RTTI object for a public struct type has public visiblity. - if (typeInst->findDecoration<IRPublicDecoration>()) + + // Make sure the RTTI object for an exported struct type is marked as export if the type is. + if (typeInst->findDecoration<IRHLSLExportDecoration>()) { - builder->addPublicDecoration(result); + builder->addHLSLExportDecoration(result); builder->addKeepAliveDecoration(result); } mapTypeToRTTIObject[typeInst] = result; diff --git a/source/slang/slang-ir-link.cpp b/source/slang/slang-ir-link.cpp index 87b4f3fde..36769cc34 100644 --- a/source/slang/slang-ir-link.cpp +++ b/source/slang/slang-ir-link.cpp @@ -1412,13 +1412,12 @@ struct IRSpecializationState } }; -static bool _isPublicOrHLSLExported(IRInst* inst) +static bool _isHLSLExported(IRInst* inst) { for (auto decoration : inst->getDecorations()) { const auto op = decoration->getOp(); - if (op == kIROp_PublicDecoration || - op == kIROp_HLSLExportDecoration) + if (op == kIROp_HLSLExportDecoration) { return true; } @@ -1582,8 +1581,8 @@ LinkedIR linkIR( { for (auto inst : irModule->getGlobalInsts()) { - // Is it `public` or (HLSL) `export` clone - if (_isPublicOrHLSLExported(inst)) + // Is it (HLSL) `export` clone + if (_isHLSLExported(inst)) { auto cloned = cloneValue(context, inst); if (!cloned->findDecorationImpl(kIROp_KeepAliveDecoration)) diff --git a/source/slang/slang-ir-lower-generic-type.cpp b/source/slang/slang-ir-lower-generic-type.cpp index ae085145c..28eed3582 100644 --- a/source/slang/slang-ir-lower-generic-type.cpp +++ b/source/slang/slang-ir-lower-generic-type.cpp @@ -16,10 +16,10 @@ namespace Slang IRInst* processInst(IRInst* inst) { - // Ensure public struct types has RTTI object defined. + // Ensure exported struct types has RTTI object defined. if (as<IRStructType>(inst)) { - if (inst->findDecoration<IRPublicDecoration>()) + if (inst->findDecoration<IRHLSLExportDecoration>()) { sharedContext->maybeEmitRTTIObject(inst); } diff --git a/source/slang/slang-ir-pytorch-cpp-binding.cpp b/source/slang/slang-ir-pytorch-cpp-binding.cpp index 432cd93f3..6a85f0324 100644 --- a/source/slang/slang-ir-pytorch-cpp-binding.cpp +++ b/source/slang/slang-ir-pytorch-cpp-binding.cpp @@ -575,7 +575,7 @@ void generateReflectionFunc(IRBuilder* builder, IRFunc* kernelFunc, IRFunc* host builder->addExternCppDecoration(reflectionFunc, reflFuncExportName.getUnownedSlice()); builder->addTorchEntryPointDecoration(reflectionFunc, reflFuncExportName.getUnownedSlice()); - builder->addPublicDecoration(reflectionFunc); + builder->addHLSLExportDecoration(reflectionFunc); builder->addKeepAliveDecoration(reflectionFunc); } @@ -760,7 +760,7 @@ void generateReflectionForType(IRType* type, DiagnosticSink* sink) builder.addTorchEntryPointDecoration(reflFunc, reflFuncExportName.getUnownedSlice()); builder.addExternCppDecoration(reflFunc, reflFuncExportName.getUnownedSlice()); - builder.addPublicDecoration(reflFunc); + builder.addHLSLExportDecoration(reflFunc); builder.addKeepAliveDecoration(reflFunc); } @@ -842,7 +842,7 @@ IRFunc* generateCUDAWrapperForFunc(IRFunc* func, DiagnosticSink* sink) // Mark for host-side emit logic. builder.addCudaHostDecoration(hostFunc); // Keep alive. This method will be accessed externally. - builder.addPublicDecoration(hostFunc); + builder.addHLSLExportDecoration(hostFunc); builder.addKeepAliveDecoration(hostFunc); } @@ -1047,7 +1047,7 @@ void generateDerivativeWrappers(IRModule* module, DiagnosticSink* sink) builder.addExternCppDecoration(wrapperFunc, nameBuilder.getUnownedSlice()); } - builder.addPublicDecoration(wrapperFunc); + builder.addHLSLExportDecoration(wrapperFunc); builder.addKeepAliveDecoration(wrapperFunc); builder.addCudaKernelForwardDerivativeDecoration(func, wrapperFunc); @@ -1106,7 +1106,7 @@ void generateDerivativeWrappers(IRModule* module, DiagnosticSink* sink) builder.addExternCppDecoration(wrapperFunc, nameBuilder.getUnownedSlice()); } - builder.addPublicDecoration(wrapperFunc); + builder.addHLSLExportDecoration(wrapperFunc); builder.addKeepAliveDecoration(wrapperFunc); builder.addCudaKernelBackwardDerivativeDecoration(func, wrapperFunc); diff --git a/source/slang/slang-language-server-completion.cpp b/source/slang/slang-language-server-completion.cpp index 7b01dac34..6038a432a 100644 --- a/source/slang/slang-language-server-completion.cpp +++ b/source/slang/slang-language-server-completion.cpp @@ -298,7 +298,7 @@ SlangResult CompletionContext::tryCompleteImport() Index pos = -1; for (auto prefix : prefixes) { - static auto importStr = UnownedStringSlice(prefix); + auto importStr = UnownedStringSlice(prefix); lineContent = doc->getLine(line); pos = lineContent.indexOf(importStr); if (pos == -1) diff --git a/source/slang/slang-lookup.cpp b/source/slang/slang-lookup.cpp index ee4518c20..04a855c3c 100644 --- a/source/slang/slang-lookup.cpp +++ b/source/slang/slang-lookup.cpp @@ -98,6 +98,19 @@ void AddToLookupResult( } } +void AddToLookupResult(LookupResult& result, const LookupResult& items) +{ + if (items.isOverloaded()) + { + for (auto item : items.items) + AddToLookupResult(result, item); + } + else if (items.isValid()) + { + AddToLookupResult(result, items.item); + } +} + LookupResult refineLookup(LookupResult const& inResult, LookupMask mask) { if (!inResult.isValid()) return inResult; @@ -894,11 +907,12 @@ LookupResult lookUpMember( SemanticsVisitor* semantics, Name* name, Type* type, + Scope* sourceScope, LookupMask mask, LookupOptions options) { LookupResult result; - LookupRequest request = initLookupRequest(semantics, name, mask, options, nullptr); + LookupRequest request = initLookupRequest(semantics, name, mask, options, sourceScope); _lookUpMembersInType(astBuilder, name, type, request, result, nullptr); return result; } diff --git a/source/slang/slang-lookup.h b/source/slang/slang-lookup.h index 8af760f70..84b453bf2 100644 --- a/source/slang/slang-lookup.h +++ b/source/slang/slang-lookup.h @@ -27,6 +27,7 @@ LookupResult lookUpMember( SemanticsVisitor* semantics, Name* name, Type* type, + Scope* sourceScope, LookupMask mask = LookupMask::Default, LookupOptions options = LookupOptions::None); @@ -58,7 +59,9 @@ QualType getTypeForDeclRef( void AddToLookupResult( LookupResult& result, LookupResultItem item); - +void AddToLookupResult( + LookupResult& result, + const LookupResult& items); } #endif diff --git a/source/slang/slang-lower-to-ir.cpp b/source/slang/slang-lower-to-ir.cpp index 609a5d1e5..8f94b7e90 100644 --- a/source/slang/slang-lower-to-ir.cpp +++ b/source/slang/slang-lower-to-ir.cpp @@ -1327,7 +1327,6 @@ static void addLinkageDecoration( if (as<PublicModifier>(modifier)) { builder->addPublicDecoration(inst); - builder->addKeepAliveDecoration(inst); } else if (as<HLSLExportModifier>(modifier)) { @@ -1349,43 +1348,50 @@ static void addLinkageDecoration( else if (as<DllExportAttribute>(modifier)) { builder->addDllExportDecoration(inst, decl->getName()->text.getUnownedSlice()); - builder->addPublicDecoration(inst); + builder->addHLSLExportDecoration(inst); + builder->addKeepAliveDecoration(inst); } else if (as<CudaDeviceExportAttribute>(modifier)) { builder->addCudaDeviceExportDecoration(inst, decl->getName()->text.getUnownedSlice()); - builder->addPublicDecoration(inst); + builder->addHLSLExportDecoration(inst); builder->addExternCppDecoration(inst, decl->getName()->text.getUnownedSlice()); + builder->addKeepAliveDecoration(inst); } else if (as<CudaHostAttribute>(modifier)) { builder->addCudaHostDecoration(inst); builder->addExternCppDecoration(inst, decl->getName()->text.getUnownedSlice()); + builder->addKeepAliveDecoration(inst); } else if (as<CudaKernelAttribute>(modifier)) { builder->addCudaKernelDecoration(inst); builder->addExternCppDecoration(inst, decl->getName()->text.getUnownedSlice()); - builder->addPublicDecoration(inst); + builder->addHLSLExportDecoration(inst); builder->addKeepAliveDecoration(inst); } else if (as<TorchEntryPointAttribute>(modifier)) { builder->addTorchEntryPointDecoration(inst, decl->getName()->text.getUnownedSlice()); builder->addCudaHostDecoration(inst); - builder->addPublicDecoration(inst); + builder->addHLSLExportDecoration(inst); + builder->addKeepAliveDecoration(inst); builder->addExternCppDecoration(inst, decl->getName()->text.getUnownedSlice()); } else if (as<AutoPyBindCudaAttribute>(modifier)) { builder->addAutoPyBindCudaDecoration(inst, decl->getName()->text.getUnownedSlice()); builder->addAutoPyBindExportInfoDecoration(inst); + builder->addKeepAliveDecoration(inst); + builder->addHLSLExportDecoration(inst); } else if (auto pyExportModifier = as<PyExportAttribute>(modifier)) { builder->addPyExportDecoration(inst, pyExportModifier->name.getLength() ? pyExportModifier->name.getUnownedSlice() : decl->getName()->text.getUnownedSlice()); + builder->addHLSLExportDecoration(inst); } else if (auto knownBuiltinModifier = as<KnownBuiltinAttribute>(modifier)) { @@ -7012,15 +7018,11 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> return LoweredValInfo::simple(inst); } - bool isPublicType(Type* type) + bool isExportedType(Type* type) { - // TODO(JS): - // Not clear how should handle HLSLExportModifier here. - // In the HLSL spec 'export' is only applicable to functions. So for now we ignore. - if (auto declRefType = as<DeclRefType>(type)) { - if (declRefType->getDeclRef().getDecl()->findModifier<PublicModifier>()) + if (declRefType->getDeclRef().getDecl()->findModifier<HLSLExportModifier>()) return true; } return false; @@ -7077,9 +7079,9 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> astReqWitnessTable->witnessedType, astReqWitnessTable->baseType); subBuilder->addExportDecoration(irSatisfyingWitnessTable, mangledName.getUnownedSlice()); - if (isPublicType(astReqWitnessTable->witnessedType)) + if (isExportedType(astReqWitnessTable->witnessedType)) { - subBuilder->addPublicDecoration(irSatisfyingWitnessTable); + subBuilder->addHLSLExportDecoration(irSatisfyingWitnessTable); subBuilder->addKeepAliveDecoration(irSatisfyingWitnessTable); } @@ -7219,17 +7221,12 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> subBuilder->addPublicDecoration(irWitnessTable); } - // TODO(JS): - // Not clear what to do here around HLSLExportModifier. - // In HLSL it only (currently) applies to functions, so perhaps do nothing is reasonable. - - if (parentDecl->findModifier<PublicModifier>()) + if (parentDecl->findModifier<HLSLExportModifier>()) { - subBuilder->addPublicDecoration(irWitnessTable); + subBuilder->addHLSLExportDecoration(irWitnessTable); subBuilder->addKeepAliveDecoration(irWitnessTable); } - // Make sure that all the entries in the witness table have been filled in, // including any cases where there are sub-witness-tables for conformances Dictionary<WitnessTable*, IRWitnessTable*> mapASTToIRWitnessTable; @@ -10607,7 +10604,9 @@ struct TypeConformanceIRGenContext context->irBuilder = builder; auto witness = lowerSimpleVal(context, typeConformance->getSubtypeWitness()); - builder->addPublicDecoration(witness); + builder->addKeepAliveDecoration(witness); + builder->addHLSLExportDecoration(witness); + if (conformanceIdOverride != -1) { builder->addSequentialIDDecoration(witness, conformanceIdOverride); diff --git a/source/slang/slang-parser.cpp b/source/slang/slang-parser.cpp index 350bc9443..7367007e6 100644 --- a/source/slang/slang-parser.cpp +++ b/source/slang/slang-parser.cpp @@ -105,6 +105,7 @@ namespace Slang Scope* outerScope = nullptr; Scope* currentScope = nullptr; + ModuleDecl* currentModule = nullptr; bool hasSeenCompletionToken = false; @@ -153,12 +154,7 @@ namespace Slang ModuleDecl* getCurrentModuleDecl() { - for (auto scope = currentScope; scope; scope = scope->parent) - { - if (auto moduleDecl = as<ModuleDecl>(scope->containerDecl)) - return moduleDecl; - } - return nullptr; + return currentModule; } Parser( @@ -1157,7 +1153,11 @@ namespace Slang { parsedModifier->loc = nameToken.loc; } - + if (as<VisibilityModifier>(parsedModifier)) + { + if (auto currentModule = parser->getCurrentModuleDecl()) + currentModule->isInLegacyLanguage = false; + } AddModifier(&modifierLink, parsedModifier); continue; } @@ -1262,6 +1262,8 @@ namespace Slang { auto decl = parser->astBuilder->create<IncludeDecl>(); parseFileReferenceDeclBase(parser, decl); + if (auto currentModule = parser->getCurrentModuleDecl()) + currentModule->isInLegacyLanguage = false; return decl; } @@ -1296,6 +1298,8 @@ namespace Slang decl->nameAndLoc.loc = parser->tokenReader.peekLoc(); } parser->ReadToken(TokenType::Semicolon); + if (auto currentModule = parser->getCurrentModuleDecl()) + currentModule->isInLegacyLanguage = false; return decl; } @@ -3063,6 +3067,9 @@ namespace Slang // The first is a type declaration that holds all the members, while // the second is a variable declaration that uses the buffer type. StructDecl* bufferDataTypeDecl = parser->astBuilder->create<StructDecl>(); + + addModifier(bufferDataTypeDecl, parser->astBuilder->create<PublicModifier>()); + VarDecl* bufferVarDecl = parser->astBuilder->create<VarDecl>(); // Both declarations will have a location that points to the name @@ -3646,6 +3653,7 @@ namespace Slang decl->nameAndLoc = declaratorInfo.nameAndLoc; decl->type = TypeExp(declaratorInfo.typeSpec); + decl->loc = decl->nameAndLoc.loc; } parseStorageDeclBody(parser, decl); @@ -4238,6 +4246,8 @@ namespace Slang currentScope = outerScope; } + currentModule = getModuleDecl(program); + PushScope(program); // A single `ModuleDecl` might span multiple source files, so it @@ -6997,7 +7007,7 @@ namespace Slang syntaxDecl->syntaxClass = syntaxClass; syntaxDecl->parseCallback = callback; syntaxDecl->parseUserData = userData; - + addModifier(syntaxDecl, globalASTBuilder->create<PublicModifier>()); AddMember(scope, syntaxDecl); } @@ -7511,6 +7521,9 @@ namespace Slang _makeParseModifier("inline", InlineModifier::kReflectClassInfo), _makeParseModifier("public", PublicModifier::kReflectClassInfo), + _makeParseModifier("private", PrivateModifier::kReflectClassInfo), + _makeParseModifier("internal", InternalModifier::kReflectClassInfo), + _makeParseModifier("require", RequireModifier::kReflectClassInfo), _makeParseModifier("param", ParamModifier::kReflectClassInfo), _makeParseModifier("extern", ExternModifier::kReflectClassInfo), diff --git a/source/slang/slang-syntax.cpp b/source/slang/slang-syntax.cpp index 53a02ed87..678d9ec26 100644 --- a/source/slang/slang-syntax.cpp +++ b/source/slang/slang-syntax.cpp @@ -765,6 +765,17 @@ Module* getModule(Decl* decl) return moduleDecl->module; } +ModuleDecl* getModuleDecl(Scope* scope) +{ + for (; scope; scope = scope->parent) + { + if (scope->containerDecl) + return getModuleDecl(scope->containerDecl); + } + return nullptr; + +} + Decl* getParentDecl(Decl* decl) { decl = decl->parentDecl; diff --git a/source/slang/slang-syntax.h b/source/slang/slang-syntax.h index b2b5deb22..fff567049 100644 --- a/source/slang/slang-syntax.h +++ b/source/slang/slang-syntax.h @@ -330,6 +330,7 @@ namespace Slang /// Get the module dclaration that a declaration is associated with, if any. ModuleDecl* getModuleDecl(Decl* decl); + ModuleDecl* getModuleDecl(Scope* scope); /// Get the module that a declaration is associated with, if any. Module* getModule(Decl* decl); |
