// Copyright 2021 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
//    list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
//    contributors may be used to endorse or promote products derived from
//    this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include "src/tint/lang/wgsl/resolver/resolver_helper_test.h"

namespace tint::resolver {
namespace {

using namespace tint::core::fluent_types;     // NOLINT
using namespace tint::core::number_suffixes;  // NOLINT

using ResolverAddressSpaceValidationTest = ResolverTest;

TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_NoAddressSpace_Fail) {
    EXPECT_ERROR("var g : f32;",
                 R"(
input.wgsl:1:1 error: module-scope 'var' declarations that are not of texture or sampler types must provide an address space
var g : f32;
^^^^^^^^^^^
)");
}

TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_NoAddressSpace_Fail) {
    EXPECT_ERROR("alias g = ptr<f32>;",
                 R"(
input.wgsl:1:11 error: 'ptr' requires at least 2 template arguments
alias g = ptr<f32>;
          ^^^^^^^^
)");
}

TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_FunctionAddressSpace_Fail) {
    EXPECT_ERROR("var<function> g : f32;",
                 R"(
input.wgsl:1:1 error: module-scope 'var' must not use address space 'function'
var<function> g : f32;
^^^^^^^^^^^^^^^^^^^^^
)");
}

TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_Private_RuntimeArray) {
    EXPECT_ERROR("var<private> v : array<i32>;", R"(
input.wgsl:1:1 error: variables in 'private' address space must have a fixed footprint
var<private> v : array<i32>;
^^^^^^^^^^^^^^^^^^^^^^^^^^^
)");
}

TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_Private_RuntimeArray) {
    EXPECT_SUCCESS("alias t = ptr<private, array<i32>>;");
}

TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_Private_RuntimeArrayInStruct) {
    EXPECT_ERROR(R"(
struct S { m : array<i32> };
var<private> v : S;
)",
                 R"(
input.wgsl:3:1 error: variables in 'private' address space must have a fixed footprint
var<private> v : S;
^^^^^^^^^^^^^^^^^^
)");
}

TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_Private_RuntimeArrayInStruct) {
    EXPECT_SUCCESS(R"(
struct S { m : array<i32> };
alias t = ptr<private, S>;
)");
}

TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_Workgroup_RuntimeArray) {
    EXPECT_ERROR(R"(
var<workgroup> v : array<i32>;
)",
                 R"(
input.wgsl:2:1 error: variables in 'workgroup' address space must have a fixed footprint
var<workgroup> v : array<i32>;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
)");
}

TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_Workgroup_RuntimeArray) {
    EXPECT_SUCCESS(R"(
alias t = ptr<workgroup, array<i32>>;
)");
}

TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_Workgroup_RuntimeArrayInStruct) {
    EXPECT_ERROR(R"(
struct S { m : array<i32> };
var<workgroup> v : S;
)",
                 R"(
input.wgsl:3:1 error: variables in 'workgroup' address space must have a fixed footprint
var<workgroup> v : S;
^^^^^^^^^^^^^^^^^^^^
)");
}

TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_Workgroup_RuntimeArrayInStruct) {
    EXPECT_SUCCESS(R"(
struct S { m : array<i32> };
alias t = ptr<workgroup, S>;
)");
}

TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_Storage_Bool) {
    EXPECT_ERROR("@group(0) @binding(0) var<storage> g : bool;", R"(
input.wgsl:1:40 error: type 'bool' cannot be used in address space 'storage' as it is non-host-shareable
@group(0) @binding(0) var<storage> g : bool;
                                       ^^^^

input.wgsl:1:23 note: while instantiating 'var' g
@group(0) @binding(0) var<storage> g : bool;
                      ^^^^^^^^^^^^^^^^^^^^^
)");
}

TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_Storage_Bool) {
    EXPECT_ERROR("alias t = ptr<storage, bool>;", R"(
input.wgsl:1:24 error: type 'bool' cannot be used in address space 'storage' as it is non-host-shareable
alias t = ptr<storage, bool>;
                       ^^^^

input.wgsl:1:11 note: while instantiating ptr<storage, bool, read>
alias t = ptr<storage, bool>;
          ^^^^^^^^^^^^^^^^^^
)");
}

TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_Storage_BoolAlias) {
    EXPECT_ERROR(R"(
alias a = bool;
@binding(0) @group(0) var<storage, read> g : a;
)",
                 R"(
input.wgsl:3:46 error: type 'bool' cannot be used in address space 'storage' as it is non-host-shareable
@binding(0) @group(0) var<storage, read> g : a;
                                             ^

input.wgsl:3:23 note: while instantiating 'var' g
@binding(0) @group(0) var<storage, read> g : a;
                      ^^^^^^^^^^^^^^^^^^^^^^^^
)");
}

TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_Storage_BoolAlias) {
    EXPECT_ERROR(R"(
alias a = bool;
alias t = ptr<storage, a>;
)",
                 R"(
input.wgsl:3:24 error: type 'bool' cannot be used in address space 'storage' as it is non-host-shareable
alias t = ptr<storage, a>;
                       ^

input.wgsl:3:11 note: while instantiating ptr<storage, bool, read>
alias t = ptr<storage, a>;
          ^^^^^^^^^^^^^^^
)");
}

TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_Storage_Pointer) {
    EXPECT_ERROR(R"(
@group(0) @binding(0) var<storage> g : ptr<private, f32>;
)",
                 R"(
input.wgsl:2:40 error: type 'ptr<private, f32, read_write>' cannot be used in address space 'storage' as it is non-host-shareable
@group(0) @binding(0) var<storage> g : ptr<private, f32>;
                                       ^^^^^^^^^^^^^^^^^

input.wgsl:2:23 note: while instantiating 'var' g
@group(0) @binding(0) var<storage> g : ptr<private, f32>;
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
)");
}

TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_Storage_IntScalar) {
    EXPECT_SUCCESS("@group(0) @binding(0) var<storage> g : i32;");
}

TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_Storage_IntScalar) {
    EXPECT_SUCCESS("alias t = ptr<storage, i32>;");
}

TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_Storage_F16) {
    EXPECT_SUCCESS(R"(
enable f16;
@group(0) @binding(0) var<storage> g : f16;
)");
}

TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_Storage_F16) {
    EXPECT_SUCCESS(R"(
enable f16;
alias t = ptr<storage, f16>;
)");
}

TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_Storage_F16Alias) {
    EXPECT_SUCCESS(R"(
enable f16;
alias a = f16;
@group(0) @binding(0) var<storage, read> g : a;
)");
}

TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_Storage_F16Alias) {
    EXPECT_SUCCESS(R"(
enable f16;
alias a = f16;
alias t = ptr<storage, a>;
)");
}

TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_Storage_VectorF32) {
    EXPECT_SUCCESS("@group(0) @binding(0) var<storage> g : vec4<f32>;");
}

TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_Storage_VectorF32) {
    EXPECT_SUCCESS("alias t = ptr<storage, vec4<f32>>;");
}

TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_Storage_VectorF16) {
    EXPECT_SUCCESS(R"(
enable f16;
@group(0) @binding(0) var<storage> g : vec4<f16>;
)");
}

TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_Storage_VectorF16) {
    EXPECT_SUCCESS(R"(
enable f16;
alias t = ptr<storage, vec4<f16>>;
)");
}

TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_Storage_ArrayF32) {
    EXPECT_SUCCESS(R"(
struct S{ a : f32 };
@group(0) @binding(0) var<storage, read> g : array<S, 3u>;
)");
}

TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_Storage_ArrayF32) {
    EXPECT_SUCCESS(R"(
struct S{ a : f32 };
alias t = ptr<storage, array<S, 3u>>;
)");
}

TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_Storage_ArrayF16) {
    EXPECT_SUCCESS(R"(
enable f16;

struct S {
  a : f16,
};
@group(0) @binding(0) var<storage, read> g : array<S, 3u>;
)");
}

TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_Storage_ArrayF16) {
    EXPECT_SUCCESS(R"(
enable f16;

struct S {
  a : f16
};
alias t = ptr<storage, array<S, 3u>, read>;
)");
}

TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_Storage_StructI32) {
    EXPECT_SUCCESS(R"(
struct S {
  x : i32,
};
@group(0) @binding(0) var<storage, read> g : S;
)");
}

TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_Storage_StructI32) {
    EXPECT_SUCCESS(R"(
struct S {
  x: i32,
};
alias t = ptr<storage, S, read_write>;
)");
}

TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_Storage_StructI32Aliases) {
    EXPECT_SUCCESS(R"(
struct S {
  x : i32
};
alias a1 = S;
alias a2 = a1;
@group(0) @binding(0) var<storage, read> g : a2;
)");
}

TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_Storage_StructI32Aliases) {
    EXPECT_SUCCESS(R"(
struct S {
  x : i32
};
alias a1 = S;
alias a2 = a1;
alias t = ptr<storage, a2, read>;
)");
}

TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_Storage_StructF16) {
    EXPECT_SUCCESS(R"(
enable f16;

struct S {
  x : f16
};
@group(0) @binding(0) var<storage, read> g : S;
)");
}

TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_Storage_StructF16) {
    EXPECT_SUCCESS(R"(
enable f16;

struct S {
  x : f16
};
alias t = ptr<storage, S, read>;
)");
}

TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_Storage_StructF16Aliases) {
    EXPECT_SUCCESS(R"(
enable f16;

struct S {
  x : f16
};
alias a1 = S;
alias a2 = a1;
@group(0) @binding(0) var<storage, read> g : a2;
)");
}

TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_Storage_StructF16Aliases) {
    EXPECT_SUCCESS(R"(
enable f16;

struct S {
  x : f16
};
alias a1 = S;
alias a2 = a1;
alias t = ptr<storage, a2, read>;
)");
}

TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_NotStorage_AccessMode) {
    EXPECT_ERROR(R"(
var<private, read> g : i32;
)",
                 R"(
input.wgsl:2:1 error: only variables in <storage> address space may specify an access mode
var<private, read> g : i32;
^^^^^^^^^^^^^^^^^^^^^^^^^^
)");
}

TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_NotStorage_AccessMode) {
    EXPECT_ERROR(R"(
alias t = ptr<private, i32, read>;
)",
                 R"(
input.wgsl:2:11 error: only pointers in <storage> address space may specify an access mode
alias t = ptr<private, i32, read>;
          ^^^^^^^^^^^^^^^^^^^^^^^
)");
}

TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_Storage_ReadAccessMode) {
    EXPECT_SUCCESS("@group(0) @binding(0) var<storage, read> a : i32;");
}

TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_Storage_ReadAccessMode) {
    EXPECT_SUCCESS("alias t = ptr<storage, i32, read>;");
}

TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_Storage_ReadWriteAccessMode) {
    EXPECT_SUCCESS("@group(0) @binding(0) var<storage, read_write> a : i32;");
}

TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_Storage_ReadWriteAccessMode) {
    EXPECT_SUCCESS("alias t = ptr<storage, i32, read_write>;");
}

TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_Storage_WriteAccessMode) {
    EXPECT_ERROR(R"(
@group(0) @binding(0) var<storage, write> a : i32;
)",
                 R"(
input.wgsl:2:23 error: access mode 'write' is not valid for the 'storage' address space
@group(0) @binding(0) var<storage, write> a : i32;
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^
)");
}

TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_Storage_WriteAccessMode) {
    EXPECT_ERROR(R"(
alias t = ptr<storage, i32, write>;
)",
                 R"(
input.wgsl:2:11 error: access mode 'write' is not valid for the 'storage' address space
alias t = ptr<storage, i32, write>;
          ^^^^^^^^^^^^^^^^^^^^^^^^
)");
}

TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_UniformBuffer_Struct_Runtime) {
    EXPECT_ERROR(R"(
struct S {
  m: array<i32>,
};
@group(0) @binding(0) var<uniform> svar : S;
)",
                 R"(
input.wgsl:5:23 error: variables in 'uniform' address space must have a fixed footprint
@group(0) @binding(0) var<uniform> svar : S;
                      ^^^^^^^^^^^^^^^^^^^^^
)");
}

TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_UniformBuffer_Struct_Runtime) {
    EXPECT_SUCCESS(R"(
struct S {
  m: array<i32>,
};
alias t = ptr<uniform, S>;
)");
}

TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_UniformBufferBool) {
    EXPECT_ERROR(R"(
@group(0) @binding(0) var<uniform> g : bool;
)",
                 R"(
input.wgsl:2:40 error: type 'bool' cannot be used in address space 'uniform' as it is non-host-shareable
@group(0) @binding(0) var<uniform> g : bool;
                                       ^^^^

input.wgsl:2:23 note: while instantiating 'var' g
@group(0) @binding(0) var<uniform> g : bool;
                      ^^^^^^^^^^^^^^^^^^^^^
)");
}

TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_UniformBufferBool) {
    EXPECT_ERROR(R"(
alias t = ptr<uniform, bool>;
)",
                 R"(
input.wgsl:2:24 error: type 'bool' cannot be used in address space 'uniform' as it is non-host-shareable
alias t = ptr<uniform, bool>;
                       ^^^^

input.wgsl:2:11 note: while instantiating ptr<uniform, bool, read>
alias t = ptr<uniform, bool>;
          ^^^^^^^^^^^^^^^^^^
)");
}

TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_UniformBufferBoolAlias) {
    EXPECT_ERROR(R"(
alias a = bool;
@group(0) @binding(0) var<uniform> g : a;
)",
                 R"(
input.wgsl:3:40 error: type 'bool' cannot be used in address space 'uniform' as it is non-host-shareable
@group(0) @binding(0) var<uniform> g : a;
                                       ^

input.wgsl:3:23 note: while instantiating 'var' g
@group(0) @binding(0) var<uniform> g : a;
                      ^^^^^^^^^^^^^^^^^^
)");
}

TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_UniformBufferBoolAlias) {
    EXPECT_ERROR(R"(
alias a = bool;
alias t = ptr<uniform, a>;
)",
                 R"(
input.wgsl:3:24 error: type 'bool' cannot be used in address space 'uniform' as it is non-host-shareable
alias t = ptr<uniform, a>;
                       ^

input.wgsl:3:11 note: while instantiating ptr<uniform, bool, read>
alias t = ptr<uniform, a>;
          ^^^^^^^^^^^^^^^
)");
}

TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_UniformPointer) {
    EXPECT_ERROR(R"(
@group(0) @binding(0) var<uniform> g : ptr<private, f32>;
)",
                 R"(
input.wgsl:2:40 error: type 'ptr<private, f32, read_write>' cannot be used in address space 'uniform' as it is non-host-shareable
@group(0) @binding(0) var<uniform> g : ptr<private, f32>;
                                       ^^^^^^^^^^^^^^^^^

input.wgsl:2:23 note: while instantiating 'var' g
@group(0) @binding(0) var<uniform> g : ptr<private, f32>;
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
)");
}

TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_UniformBufferIntScalar) {
    EXPECT_SUCCESS("@group(0) @binding(0) var<uniform> g : i32;");
}

TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_UniformBufferIntScalar) {
    EXPECT_SUCCESS("alias t = ptr<uniform, i32>;");
}

TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_UniformBufferF16) {
    EXPECT_SUCCESS(R"(
enable f16;

@group(0) @binding(0) var<uniform> g : f16;
)");
}

TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_UniformBufferF16) {
    EXPECT_SUCCESS(R"(
enable f16;

alias t = ptr<uniform, f16>;
)");
}

TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_UniformBufferVectorF32) {
    EXPECT_SUCCESS("@group(0) @binding(0) var<uniform> g : vec4<f32>;");
}

TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_UniformBufferVectorF32) {
    EXPECT_SUCCESS("alias t = ptr<uniform, vec4<f32>>;");
}

TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_UniformBufferVectorF16) {
    EXPECT_SUCCESS(R"(
enable f16;

@group(0) @binding(0) var<uniform> g : vec4<f16>;
)");
}

TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_UniformBufferVectorF16) {
    EXPECT_SUCCESS(R"(
enable f16;

alias t = ptr<uniform, f16>;
)");
}

TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_UniformBufferArrayF32) {
    EXPECT_SUCCESS(R"(
struct S {
   @size(16) f : f32,
}
@group(0) @binding(0) var<uniform> g : array<S, 3u>;
)");
}

TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_UniformBufferArrayF32) {
    EXPECT_SUCCESS(R"(
struct S {
  @size(16) f : f32,
}
alias t = ptr<uniform, array<S, 3u>>;
)");
}

TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_UniformBufferArrayF16) {
    EXPECT_SUCCESS(R"(
enable f16;

struct S {
   @size(16) f : f16,
}
@group(0) @binding(0) var<uniform> g : array<S, 3u>;
)");
}

TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_UniformBufferArrayF16) {
    EXPECT_SUCCESS(R"(
enable f16;

struct S {
  @size(16) f : f16,
}
alias t = ptr<uniform, array<S, 3u>>;
)");
}

TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_UniformBufferStructI32) {
    EXPECT_SUCCESS(R"(
struct S {
  x : i32
};
@group(0) @binding(0) var<uniform> g : S;
)");
}

TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_UniformBufferStructI32) {
    EXPECT_SUCCESS(R"(
struct S {
  x : i32,
};
alias t = ptr<uniform, S>;
)");
}

TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_UniformBufferStructI32Aliases) {
    EXPECT_SUCCESS(R"(
struct S {
  x : i32
};
alias a1 = S;
@group(0) @binding(0) var<uniform> g : a1;
)");
}

TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_UniformBufferStructI32Aliases) {
    EXPECT_SUCCESS(R"(
struct S {
  x : i32
};
alias a1 = S;
alias t = ptr<uniform, a1>;
)");
}

TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_UniformBufferStructF16) {
    EXPECT_SUCCESS(R"(
enable f16;

struct S {
  x : f16
};
@group(0) @binding(0) var<uniform> g : S;
)");
}

TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_UniformBufferStructF16) {
    EXPECT_SUCCESS(R"(
enable f16;

struct S {
  x : f16
};
alias t = ptr<uniform, S>;
)");
}

TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_UniformBufferStructF16Aliases) {
    EXPECT_SUCCESS(R"(
enable f16;

struct S {
  x : f16
};
alias a1 = S;
@group(0) @binding(0) var<uniform> g : a1;
)");
}

TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_UniformBufferStructF16Aliases) {
    EXPECT_SUCCESS(R"(
enable f16;

struct S {
  x : f16
};
alias a1 = S;
alias t = ptr<uniform, a1>;
)");
}

TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_ImmediateBool) {
    EXPECT_ERROR(R"(
var<immediate> g : bool;
)",
                 R"(
input.wgsl:2:20 error: type 'bool' cannot be used in address space 'immediate' as it is non-host-shareable
var<immediate> g : bool;
                   ^^^^

input.wgsl:2:1 note: while instantiating 'var' g
var<immediate> g : bool;
^^^^^^^^^^^^^^^^^^^^^^^
)");
}

TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_ImmediateBool) {
    EXPECT_ERROR(R"(
alias t = ptr<immediate, bool>;
)",
                 R"(
input.wgsl:2:26 error: type 'bool' cannot be used in address space 'immediate' as it is non-host-shareable
alias t = ptr<immediate, bool>;
                         ^^^^

input.wgsl:2:11 note: while instantiating ptr<immediate, bool, read>
alias t = ptr<immediate, bool>;
          ^^^^^^^^^^^^^^^^^^^^
)");
}

TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_ImmediateF16) {
    EXPECT_ERROR(R"(
enable f16;

var<immediate> g : f16;
)",
                 R"(
input.wgsl:4:1 error: using 'f16' in 'immediate' address space is not implemented yet
var<immediate> g : f16;
^^^^^^^^^^^^^^^^^^^^^^
)");
}

TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_ImmediateF16) {
    EXPECT_ERROR(R"(
enable f16;

alias t = ptr<immediate, f16>;
)",
                 R"(
input.wgsl:4:11 error: using 'f16' in 'immediate' address space is not implemented yet
alias t = ptr<immediate, f16>;
          ^^^^^^^^^^^^^^^^^^^
)");
}

TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_ImmediatePointer) {
    EXPECT_ERROR(R"(
var<immediate> g : ptr<private, f32>;
)",
                 R"(
input.wgsl:2:20 error: type 'ptr<private, f32, read_write>' cannot be used in address space 'immediate' as it is non-host-shareable
var<immediate> g : ptr<private, f32>;
                   ^^^^^^^^^^^^^^^^^

input.wgsl:2:1 note: while instantiating 'var' g
var<immediate> g : ptr<private, f32>;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
)");
}

TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_ImmediateIntScalar) {
    EXPECT_SUCCESS("var<immediate> g : i32;");
}

TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_ImmediateIntScalar) {
    EXPECT_SUCCESS("alias t = ptr<immediate, i32>;");
}

TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_ImmediateVectorF32) {
    EXPECT_SUCCESS("var<immediate> g : vec4<f32>;");
}

TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_ImmediateVectorF32) {
    EXPECT_SUCCESS("var<immediate> g : vec4<f32>;");
}

TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_ImmediateArrayF32) {
    EXPECT_SUCCESS(R"(
struct S {
  a : f32
}
var<immediate> g : array<S, 3u>;
)");
}

TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_ImmediateArrayF32) {
    EXPECT_SUCCESS(R"(
struct S {
  a : f32
}
alias t = ptr<immediate, array<S, 3u>>;
)");
}

}  // namespace
}  // namespace tint::resolver
