diff --git a/common/fuzzing/carbon.proto b/common/fuzzing/carbon.proto index 97644012200a..9709377b6fb8 100644 --- a/common/fuzzing/carbon.proto +++ b/common/fuzzing/carbon.proto @@ -453,6 +453,10 @@ message MixDeclaration { optional Expression mixin = 1; } +message NamespaceDeclaration { + optional string name = 1; +} + message Declaration { oneof kind { FunctionDeclaration function = 1; @@ -470,6 +474,7 @@ message Declaration { InterfaceImplDeclaration interface_impl = 13; ConstraintDeclaration constraint = 14; MatchFirstDeclaration match_first = 15; + NamespaceDeclaration namespace = 16; } } diff --git a/common/fuzzing/proto_to_carbon.cpp b/common/fuzzing/proto_to_carbon.cpp index a22821f61e05..3c96453a90f8 100644 --- a/common/fuzzing/proto_to_carbon.cpp +++ b/common/fuzzing/proto_to_carbon.cpp @@ -718,10 +718,16 @@ static auto ReturnTermToCarbon(const Fuzzing::ReturnTerm& return_term, static auto DeclarationToCarbon(const Fuzzing::Declaration& declaration, llvm::raw_ostream& out) -> void { switch (declaration.kind_case()) { - case Fuzzing::Declaration::KIND_NOT_SET: + case Fuzzing::Declaration::KIND_NOT_SET: { // Arbitrary default to avoid getting invalid syntax. out << "var x: i32;"; break; + } + + case Fuzzing::Declaration::kNamespace: { + out << "namespace " << declaration.namespace_().name() << ";"; + break; + } case Fuzzing::Declaration::kDestructor: { const auto& function = declaration.destructor(); diff --git a/explorer/ast/ast_rtti.txt b/explorer/ast/ast_rtti.txt index 4a0bdcb1b76b..7e97604536fa 100644 --- a/explorer/ast/ast_rtti.txt +++ b/explorer/ast/ast_rtti.txt @@ -13,6 +13,7 @@ abstract class Pattern : AstNode; class AlternativePattern : Pattern; class ExpressionPattern : Pattern; abstract class Declaration : AstNode; + class NamespaceDeclaration : Declaration; abstract class CallableDeclaration : Declaration; class FunctionDeclaration : CallableDeclaration; class DestructorDeclaration : CallableDeclaration; diff --git a/explorer/ast/declaration.cpp b/explorer/ast/declaration.cpp index 7bf82dfb86ac..65158865b499 100644 --- a/explorer/ast/declaration.cpp +++ b/explorer/ast/declaration.cpp @@ -15,6 +15,10 @@ Declaration::~Declaration() = default; void Declaration::Print(llvm::raw_ostream& out) const { switch (kind()) { + case DeclarationKind::NamespaceDeclaration: + PrintID(out); + out << ";"; + break; case DeclarationKind::InterfaceDeclaration: case DeclarationKind::ConstraintDeclaration: { const auto& iface_decl = cast(*this); @@ -126,6 +130,9 @@ void Declaration::Print(llvm::raw_ostream& out) const { void Declaration::PrintID(llvm::raw_ostream& out) const { switch (kind()) { + case DeclarationKind::NamespaceDeclaration: + out << "namespace " << cast(*this).name(); + break; case DeclarationKind::InterfaceDeclaration: { const auto& iface_decl = cast(*this); out << "interface " << iface_decl.name(); @@ -221,6 +228,8 @@ void Declaration::PrintID(llvm::raw_ostream& out) const { auto GetName(const Declaration& declaration) -> std::optional { switch (declaration.kind()) { + case DeclarationKind::NamespaceDeclaration: + return cast(declaration).name(); case DeclarationKind::FunctionDeclaration: return cast(declaration).name(); case DeclarationKind::DestructorDeclaration: diff --git a/explorer/ast/declaration.h b/explorer/ast/declaration.h index b966702dd291..20e9cc7386a2 100644 --- a/explorer/ast/declaration.h +++ b/explorer/ast/declaration.h @@ -126,6 +126,26 @@ class Declaration : public AstNode { bool is_type_checked_ = false; }; +// A declaration of a namespace. +class NamespaceDeclaration : public Declaration { + public: + using ImplementsCarbonValueNode = void; + + explicit NamespaceDeclaration(SourceLocation source_loc, std::string name) + : Declaration(AstNodeKind::NamespaceDeclaration, source_loc), + name_(name) {} + + static auto classof(const AstNode* node) -> bool { + return InheritsFromNamespaceDeclaration(node->kind()); + } + + auto name() const -> std::string_view { return name_; } + auto value_category() const -> ValueCategory { return ValueCategory::Let; } + + private: + std::string name_; +}; + // A function's virtual override keyword. enum class VirtualOverride { None, Abstract, Virtual, Impl }; diff --git a/explorer/ast/static_scope.cpp b/explorer/ast/static_scope.cpp index 02c99896acb6..0f1e6ce64221 100644 --- a/explorer/ast/static_scope.cpp +++ b/explorer/ast/static_scope.cpp @@ -11,7 +11,7 @@ namespace Carbon { -auto StaticScope::Add(const std::string& name, ValueNodeView entity, +auto StaticScope::Add(std::string_view name, ValueNodeView entity, NameStatus status) -> ErrorOr { auto [it, inserted] = declared_names_.insert({name, {entity, status}}); if (!inserted) { @@ -27,7 +27,7 @@ auto StaticScope::Add(const std::string& name, ValueNodeView entity, return Success(); } -void StaticScope::MarkDeclared(const std::string& name) { +void StaticScope::MarkDeclared(std::string_view name) { auto it = declared_names_.find(name); CARBON_CHECK(it != declared_names_.end()) << name << " not found"; if (it->second.status == NameStatus::KnownButNotDeclared) { @@ -35,13 +35,13 @@ void StaticScope::MarkDeclared(const std::string& name) { } } -void StaticScope::MarkUsable(const std::string& name) { +void StaticScope::MarkUsable(std::string_view name) { auto it = declared_names_.find(name); CARBON_CHECK(it != declared_names_.end()) << name << " not found"; it->second.status = NameStatus::Usable; } -auto StaticScope::Resolve(const std::string& name, +auto StaticScope::Resolve(std::string_view name, SourceLocation source_loc) const -> ErrorOr { CARBON_ASSIGN_OR_RETURN(std::optional result, @@ -52,7 +52,7 @@ auto StaticScope::Resolve(const std::string& name, return *result; } -auto StaticScope::TryResolve(const std::string& name, +auto StaticScope::TryResolve(std::string_view name, SourceLocation source_loc) const -> ErrorOr> { for (const StaticScope* scope = this; scope; diff --git a/explorer/ast/static_scope.h b/explorer/ast/static_scope.h index 9f956931cdfe..e689c03a362a 100644 --- a/explorer/ast/static_scope.h +++ b/explorer/ast/static_scope.h @@ -6,12 +6,13 @@ #define CARBON_EXPLORER_AST_STATIC_SCOPE_H_ #include -#include +#include #include "common/error.h" #include "explorer/ast/value_node.h" #include "explorer/common/nonnull.h" #include "explorer/common/source_location.h" +#include "llvm/ADT/StringMap.h" namespace Carbon { @@ -44,18 +45,18 @@ class StaticScope { // if `name` is already defined to be a different entity in this scope. // If `usable` is `false`, `name` cannot yet be referenced and `Resolve()` // methods will fail for it. - auto Add(const std::string& name, ValueNodeView entity, + auto Add(std::string_view name, ValueNodeView entity, NameStatus status = NameStatus::Usable) -> ErrorOr; // Marks `name` as being past its point of declaration. - void MarkDeclared(const std::string& name); + void MarkDeclared(std::string_view name); // Marks `name` as being completely declared and hence usable. - void MarkUsable(const std::string& name); + void MarkUsable(std::string_view name); // Returns the nearest definition of `name` in the ancestor graph of this // scope, or reports a compilation error at `source_loc` there isn't exactly // one such definition. - auto Resolve(const std::string& name, SourceLocation source_loc) const + auto Resolve(std::string_view name, SourceLocation source_loc) const -> ErrorOr; // Returns the value node of the BindingPattern of the returned var definition @@ -71,7 +72,7 @@ class StaticScope { // Equivalent to Resolve, but returns `nullopt` instead of raising an error // if no definition can be found. Still raises a compilation error if more // than one definition is found. - auto TryResolve(const std::string& name, SourceLocation source_loc) const + auto TryResolve(std::string_view name, SourceLocation source_loc) const -> ErrorOr>; struct Entry { @@ -79,7 +80,7 @@ class StaticScope { NameStatus status; }; // Maps locally declared names to their entities. - std::unordered_map declared_names_; + llvm::StringMap declared_names_; // The parent scope of this scope, if it not the root scope. std::optional> parent_scope_; diff --git a/explorer/fuzzing/ast_to_proto.cpp b/explorer/fuzzing/ast_to_proto.cpp index ed04adfc8573..ba4375072242 100644 --- a/explorer/fuzzing/ast_to_proto.cpp +++ b/explorer/fuzzing/ast_to_proto.cpp @@ -618,6 +618,12 @@ static auto DeclarationToProto(const Declaration& declaration) -> Fuzzing::Declaration { Fuzzing::Declaration declaration_proto; switch (declaration.kind()) { + case DeclarationKind::NamespaceDeclaration: { + const auto& namespace_decl = cast(declaration); + auto* namespace_proto = declaration_proto.mutable_namespace_(); + namespace_proto->set_name(std::string(namespace_decl.name())); + break; + } case DeclarationKind::DestructorDeclaration: { const auto& function = cast(declaration); auto* function_proto = declaration_proto.mutable_destructor(); diff --git a/explorer/interpreter/interpreter.cpp b/explorer/interpreter/interpreter.cpp index 6f640d8ac3d3..66e23a163b87 100644 --- a/explorer/interpreter/interpreter.cpp +++ b/explorer/interpreter/interpreter.cpp @@ -769,6 +769,7 @@ auto Interpreter::Convert(Nonnull value, case Value::Kind::TypeOfMixinPseudoType: case Value::Kind::TypeOfParameterizedEntityName: case Value::Kind::TypeOfMemberName: + case Value::Kind::TypeOfNamespaceName: case Value::Kind::StaticArrayType: case Value::Kind::MemberName: // TODO: add `CARBON_CHECK(TypeEqual(type, value->dynamic_type()))`, once @@ -2111,6 +2112,7 @@ auto Interpreter::StepDeclaration() -> ErrorOr { return todo_.FinishAction(); } } + case DeclarationKind::NamespaceDeclaration: case DeclarationKind::DestructorDeclaration: case DeclarationKind::FunctionDeclaration: case DeclarationKind::ClassDeclaration: diff --git a/explorer/interpreter/resolve_control_flow.cpp b/explorer/interpreter/resolve_control_flow.cpp index 70fe49902b86..049aa6a08050 100644 --- a/explorer/interpreter/resolve_control_flow.cpp +++ b/explorer/interpreter/resolve_control_flow.cpp @@ -186,6 +186,7 @@ auto ResolveControlFlow(Nonnull declaration) -> ErrorOr { } break; } + case DeclarationKind::NamespaceDeclaration: case DeclarationKind::ChoiceDeclaration: case DeclarationKind::VariableDeclaration: case DeclarationKind::InterfaceExtendsDeclaration: diff --git a/explorer/interpreter/resolve_names.cpp b/explorer/interpreter/resolve_names.cpp index 7e1b50369035..de7a9a0f118b 100644 --- a/explorer/interpreter/resolve_names.cpp +++ b/explorer/interpreter/resolve_names.cpp @@ -22,6 +22,13 @@ namespace Carbon { static auto AddExposedNames(const Declaration& declaration, StaticScope& enclosing_scope) -> ErrorOr { switch (declaration.kind()) { + case DeclarationKind::NamespaceDeclaration: { + const auto& namespace_decl = cast(declaration); + CARBON_RETURN_IF_ERROR( + enclosing_scope.Add(namespace_decl.name(), &namespace_decl, + StaticScope::NameStatus::KnownButNotDeclared)); + break; + } case DeclarationKind::InterfaceDeclaration: case DeclarationKind::ConstraintDeclaration: { const auto& iface_decl = cast(declaration); @@ -519,6 +526,11 @@ static auto ResolveMemberNames(llvm::ArrayRef> members, static auto ResolveNames(Declaration& declaration, StaticScope& enclosing_scope, ResolveFunctionBodies bodies) -> ErrorOr { switch (declaration.kind()) { + case DeclarationKind::NamespaceDeclaration: { + auto& namespace_decl = cast(declaration); + enclosing_scope.MarkUsable(namespace_decl.name()); + break; + } case DeclarationKind::InterfaceDeclaration: case DeclarationKind::ConstraintDeclaration: { auto& iface = cast(declaration); @@ -569,7 +581,7 @@ static auto ResolveNames(Declaration& declaration, StaticScope& enclosing_scope, StaticScope function_scope(&enclosing_scope); const auto name = GetName(function); CARBON_CHECK(name) << "Unexpected missing name for `" << function << "`."; - enclosing_scope.MarkDeclared(std::string(*name)); + enclosing_scope.MarkDeclared(*name); for (Nonnull binding : function.deduced_parameters()) { CARBON_RETURN_IF_ERROR(ResolveNames(*binding, function_scope)); } @@ -583,7 +595,7 @@ static auto ResolveNames(Declaration& declaration, StaticScope& enclosing_scope, CARBON_RETURN_IF_ERROR(ResolveNames( **function.return_term().type_expression(), function_scope)); } - enclosing_scope.MarkUsable(std::string(*name)); + enclosing_scope.MarkUsable(*name); if (function.body().has_value() && bodies != ResolveFunctionBodies::Skip) { CARBON_RETURN_IF_ERROR(ResolveNames(**function.body(), function_scope)); diff --git a/explorer/interpreter/resolve_unformed.cpp b/explorer/interpreter/resolve_unformed.cpp index 533cb9a6176e..7b485225f04f 100644 --- a/explorer/interpreter/resolve_unformed.cpp +++ b/explorer/interpreter/resolve_unformed.cpp @@ -309,6 +309,7 @@ static auto ResolveUnformed(Nonnull declaration) } break; } + case DeclarationKind::NamespaceDeclaration: case DeclarationKind::ClassDeclaration: case DeclarationKind::MixDeclaration: case DeclarationKind::MixinDeclaration: diff --git a/explorer/interpreter/type_checker.cpp b/explorer/interpreter/type_checker.cpp index 2a9c09115e3f..192ff03f6e76 100644 --- a/explorer/interpreter/type_checker.cpp +++ b/explorer/interpreter/type_checker.cpp @@ -122,6 +122,7 @@ static auto IsTypeOfType(Nonnull value) -> bool { case Value::Kind::TypeOfMixinPseudoType: case Value::Kind::TypeOfParameterizedEntityName: case Value::Kind::TypeOfMemberName: + case Value::Kind::TypeOfNamespaceName: // These are types whose values are not types. return false; case Value::Kind::AutoType: @@ -188,6 +189,7 @@ static auto IsType(Nonnull value) -> bool { case Value::Kind::TypeOfParameterizedEntityName: case Value::Kind::TypeOfMemberName: case Value::Kind::TypeOfMixinPseudoType: + case Value::Kind::TypeOfNamespaceName: // These aren't first-class types, but they are still types. return true; case Value::Kind::AssociatedConstant: { @@ -252,7 +254,8 @@ static auto ExpectCompleteType(SourceLocation source_loc, case Value::Kind::AssociatedConstant: case Value::Kind::TypeOfParameterizedEntityName: case Value::Kind::TypeOfMemberName: - case Value::Kind::TypeOfMixinPseudoType: { + case Value::Kind::TypeOfMixinPseudoType: + case Value::Kind::TypeOfNamespaceName: { // These types are always complete. return Success(); } @@ -344,6 +347,7 @@ static auto TypeContainsAuto(Nonnull type) -> bool { case Value::Kind::TypeOfMixinPseudoType: case Value::Kind::TypeOfParameterizedEntityName: case Value::Kind::TypeOfMemberName: + case Value::Kind::TypeOfNamespaceName: // These types do not contain other types. return false; case Value::Kind::FunctionType: @@ -378,7 +382,7 @@ static auto TypeContainsAuto(Nonnull type) -> bool { static auto IsPlaceholderType(Nonnull type) -> bool { CARBON_CHECK(IsType(type)) << "expected a type, but found " << *type; return isa(type); + TypeOfMixinPseudoType, TypeOfNamespaceName>(type); } // Returns whether `value` is a concrete type, which would be valid as the @@ -826,6 +830,10 @@ auto TypeChecker::ExpectNonPlaceholderType(SourceLocation source_loc, << "invalid use of mixin " << mixin_type->mixin_type().declaration().name(); } + if (auto* namespace_type = dyn_cast(type)) { + return ProgramError(source_loc) + << "expected `.member_name` after name of " << *namespace_type; + } CARBON_FATAL() << "unknown kind of placeholder type " << *type; } @@ -1141,7 +1149,8 @@ auto TypeChecker::ArgumentDeduction::Deduce(Nonnull param, case Value::Kind::TypeType: case Value::Kind::StringType: case Value::Kind::TypeOfParameterizedEntityName: - case Value::Kind::TypeOfMemberName: { + case Value::Kind::TypeOfMemberName: + case Value::Kind::TypeOfNamespaceName: { return handle_non_deduced_type(); } case Value::Kind::ImplWitness: @@ -2842,6 +2851,11 @@ auto TypeChecker::TypeCheckExp(Nonnull e, << "unsupported member access into type " << *type; } } + case Value::Kind::TypeOfNamespaceName: { + // TODO: Implement this. + return ProgramError(e->source_loc()) + << "member access into namespace is not implemented yet"; + } default: return ProgramError(e->source_loc()) << "member access, unexpected " << object_type << " in " << *e; @@ -4297,8 +4311,10 @@ auto TypeChecker::TypeCheckStmt(Nonnull s, return Success(); } case StatementKind::ExpressionStatement: { - CARBON_RETURN_IF_ERROR(TypeCheckExp( - &cast(*s).expression(), impl_scope)); + auto& expr_stmt = cast(*s); + CARBON_RETURN_IF_ERROR(TypeCheckExp(&expr_stmt.expression(), impl_scope)); + CARBON_RETURN_IF_ERROR(ExpectNonPlaceholderType( + expr_stmt.source_loc(), &expr_stmt.expression().static_type())); return Success(); } case StatementKind::If: { @@ -5525,6 +5541,7 @@ static auto IsValidTypeForAliasTarget(Nonnull type) -> bool { case Value::Kind::TypeType: case Value::Kind::TypeOfParameterizedEntityName: case Value::Kind::TypeOfMemberName: + case Value::Kind::TypeOfNamespaceName: return true; } } @@ -5577,6 +5594,8 @@ auto TypeChecker::TypeCheckDeclaration( **trace_stream_ << "checking " << DeclarationKindName(d->kind()) << "\n"; } switch (d->kind()) { + case DeclarationKind::NamespaceDeclaration: + break; case DeclarationKind::InterfaceDeclaration: case DeclarationKind::ConstraintDeclaration: { CARBON_RETURN_IF_ERROR(TypeCheckConstraintTypeDeclaration( @@ -5661,6 +5680,12 @@ auto TypeChecker::DeclareDeclaration(Nonnull d, const ScopeInfo& scope_info) -> ErrorOr { switch (d->kind()) { + case DeclarationKind::NamespaceDeclaration: { + auto& namespace_decl = cast(*d); + namespace_decl.set_static_type( + arena_->New(&namespace_decl)); + break; + } case DeclarationKind::InterfaceDeclaration: case DeclarationKind::ConstraintDeclaration: { auto& iface_decl = cast(*d); diff --git a/explorer/interpreter/value.cpp b/explorer/interpreter/value.cpp index 2276addbc4c4..fb01cdf614f7 100644 --- a/explorer/interpreter/value.cpp +++ b/explorer/interpreter/value.cpp @@ -689,6 +689,10 @@ void Value::Print(llvm::raw_ostream& out) const { out << "member name " << cast(*this).member(); break; } + case Value::Kind::TypeOfNamespaceName: { + cast(*this).namespace_decl()->PrintID(out); + break; + } case Value::Kind::StaticArrayType: { const auto& array_type = cast(*this); out << "[" << array_type.element_type() << "; " << array_type.size() @@ -923,6 +927,7 @@ auto TypeEqual(Nonnull t1, Nonnull t2, case Value::Kind::TypeOfMemberName: case Value::Kind::MixinPseudoType: case Value::Kind::TypeOfMixinPseudoType: + case Value::Kind::TypeOfNamespaceName: CARBON_FATAL() << "TypeEqual used to compare non-type values\n" << *t1 << "\n" << *t2; @@ -1045,6 +1050,7 @@ auto ValueStructurallyEqual( case Value::Kind::TypeOfMixinPseudoType: case Value::Kind::TypeOfParameterizedEntityName: case Value::Kind::TypeOfMemberName: + case Value::Kind::TypeOfNamespaceName: case Value::Kind::StaticArrayType: return TypeEqual(v1, v2, equality_ctx); case Value::Kind::NominalClassValue: diff --git a/explorer/interpreter/value.h b/explorer/interpreter/value.h index 57c2b910e6f6..7cc0c2e4b03f 100644 --- a/explorer/interpreter/value.h +++ b/explorer/interpreter/value.h @@ -1600,6 +1600,33 @@ class TypeOfMemberName : public Value { NamedElement member_; }; +// The type of a namespace name. +// +// Such expressions can appear only as the target of an `alias` declaration or +// as the left-hand side of a simple member access expression. +class TypeOfNamespaceName : public Value { + public: + explicit TypeOfNamespaceName( + Nonnull namespace_decl) + : Value(Kind::TypeOfNamespaceName), namespace_decl_(namespace_decl) {} + + static auto classof(const Value* value) -> bool { + return value->kind() == Kind::TypeOfNamespaceName; + } + + template + auto Decompose(F f) const { + return f(namespace_decl_); + } + + auto namespace_decl() const -> Nonnull { + return namespace_decl_; + } + + private: + Nonnull namespace_decl_; +}; + // The type of a statically-sized array. // // Note that values of this type are represented as tuples. diff --git a/explorer/interpreter/value_kinds.def b/explorer/interpreter/value_kinds.def index 5fdad3b23582..58c0f9789923 100644 --- a/explorer/interpreter/value_kinds.def +++ b/explorer/interpreter/value_kinds.def @@ -54,6 +54,7 @@ CARBON_VALUE_KIND(StringValue) CARBON_VALUE_KIND(TypeOfMixinPseudoType) CARBON_VALUE_KIND(TypeOfParameterizedEntityName) CARBON_VALUE_KIND(TypeOfMemberName) +CARBON_VALUE_KIND(TypeOfNamespaceName) CARBON_VALUE_KIND(StaticArrayType) #undef CARBON_VALUE_KIND diff --git a/explorer/syntax/lexer.lpp b/explorer/syntax/lexer.lpp index 1cad583a93eb..2ca5264446c9 100644 --- a/explorer/syntax/lexer.lpp +++ b/explorer/syntax/lexer.lpp @@ -96,6 +96,7 @@ MINUS_EQUAL "-=" MINUS_MINUS "--" MIX "__mix" MIXIN "__mixin" +NAMESPACE "namespace" NOT "not" NOT_EQUAL "!=" OR "or" @@ -217,6 +218,7 @@ operand_start [(A-Za-z0-9_\"] {MINUS} { return CARBON_SIMPLE_TOKEN(MINUS); } {MIXIN} { return CARBON_SIMPLE_TOKEN(MIXIN); } {MIX} { return CARBON_SIMPLE_TOKEN(MIX); } +{NAMESPACE} { return CARBON_SIMPLE_TOKEN(NAMESPACE); } {NOT_EQUAL} { return CARBON_SIMPLE_TOKEN(NOT_EQUAL); } {NOT} { return CARBON_SIMPLE_TOKEN(NOT); } {OR} { return CARBON_SIMPLE_TOKEN(OR); } diff --git a/explorer/syntax/parser.ypp b/explorer/syntax/parser.ypp index cce8e5674bb1..4834dde4fa13 100644 --- a/explorer/syntax/parser.ypp +++ b/explorer/syntax/parser.ypp @@ -270,6 +270,7 @@ MINUS_MINUS MIX MIXIN + NAMESPACE NOT NOT_EQUAL OR @@ -1221,7 +1222,9 @@ class_declaration_extends: { $$ = $2; } ; declaration: - function_declaration + NAMESPACE identifier SEMICOLON + { $$ = arena->New(context.source_loc(), $2); } +| function_declaration { $$ = $1; } | destructor_declaration { $$ = $1; } diff --git a/explorer/testdata/namespace/declare.carbon b/explorer/testdata/namespace/declare.carbon new file mode 100644 index 000000000000..1937dfbbf449 --- /dev/null +++ b/explorer/testdata/namespace/declare.carbon @@ -0,0 +1,14 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// AUTOUPDATE +// RUN: %{explorer-run} +// RUN: %{explorer-run-trace} +// CHECK:STDOUT: result: 0 + +package ExplorerTest api; + +namespace N; + +fn Main() -> i32 { return 0; } diff --git a/explorer/testdata/namespace/fail_unknown_member.carbon b/explorer/testdata/namespace/fail_unknown_member.carbon new file mode 100644 index 000000000000..135326813092 --- /dev/null +++ b/explorer/testdata/namespace/fail_unknown_member.carbon @@ -0,0 +1,16 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// AUTOUPDATE +// RUN: %{not} %{explorer-run} +// RUN: %{not} %{explorer-run-trace} + +package ExplorerTest api; + +namespace N; + +fn Main() -> i32 { + // CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/namespace/fail_unknown_member.carbon:[[@LINE+1]]: member access into namespace is not implemented yet + return N.value; +} diff --git a/explorer/testdata/namespace/fail_use_as_expression.carbon b/explorer/testdata/namespace/fail_use_as_expression.carbon new file mode 100644 index 000000000000..8cfb4e7d849e --- /dev/null +++ b/explorer/testdata/namespace/fail_use_as_expression.carbon @@ -0,0 +1,17 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// AUTOUPDATE +// RUN: %{not} %{explorer-run} +// RUN: %{not} %{explorer-run-trace} + +package ExplorerTest api; + +namespace N; + +fn Main() -> i32 { + // CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/namespace/fail_use_as_expression.carbon:[[@LINE+1]]: expected `.member_name` after name of namespace N + N; + return 0; +} diff --git a/explorer/testdata/namespace/fail_use_as_value.carbon b/explorer/testdata/namespace/fail_use_as_value.carbon new file mode 100644 index 000000000000..476a16d385db --- /dev/null +++ b/explorer/testdata/namespace/fail_use_as_value.carbon @@ -0,0 +1,18 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// AUTOUPDATE +// RUN: %{not} %{explorer-run} +// RUN: %{not} %{explorer-run-trace} + +package ExplorerTest api; + +namespace N; + +fn F[T:! type](x: T) -> T { return x; } + +fn Main() -> i32 { + // CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/namespace/fail_use_as_value.carbon:[[@LINE+1]]: expected `.member_name` after name of namespace N + return F(N); +}