diff --git a/explorer/data/prelude.carbon b/explorer/data/prelude.carbon index 75e0f66baaae..e0e32eeff5ef 100644 --- a/explorer/data/prelude.carbon +++ b/explorer/data/prelude.carbon @@ -686,13 +686,13 @@ fn Rand(low: i32, high: i32) -> i32{ // Optional. //------------------------- choice OptionalElement(T:! type) { - None(), + None, Element(T) } class Optional(T:! type) { fn CreateEmpty() -> Optional(T) { - return {.element = OptionalElement(T).None()}; + return {.element = OptionalElement(T).None}; } fn Create(value: T) -> Optional(T) { return {.element = OptionalElement(T).Element(value)}; @@ -700,7 +700,7 @@ class Optional(T:! type) { fn HasValue[self: Self]() -> bool { match(self.element) { - case OptionalElement(T).None() => { return false; } + case OptionalElement(T).None => { return false; } } return true; } diff --git a/explorer/interpreter/pattern_analysis.cpp b/explorer/interpreter/pattern_analysis.cpp index e5501748d7e4..2ce8ab7e0785 100644 --- a/explorer/interpreter/pattern_analysis.cpp +++ b/explorer/interpreter/pattern_analysis.cpp @@ -47,16 +47,13 @@ auto AbstractPattern::elements_size() const -> int { if (const auto* tuple_pattern = dyn_cast(pattern)) { return tuple_pattern->fields().size(); } else if (isa(pattern)) { - // Note, AlternativePattern is only used for a pattern with arguments. An - // alternative pattern without arguments is represented as an - // AlternativeValue. return 1; } } else if (const auto* value = value_.dyn_cast()) { if (const auto* tuple = dyn_cast(value)) { return tuple->elements().size(); } else if (const auto* alt = dyn_cast(value)) { - return alt->argument() ? 1 : 0; + return 1; } } return 0; @@ -84,6 +81,10 @@ void AbstractPattern::AppendElementsTo( if (auto arg = alt->argument()) { out.push_back(AbstractPattern( *arg, *alt->alternative().parameters_static_type())); + } else { + // There's no value to match for this alternative, so just insert a + // wildcard. + out.push_back(AbstractPattern::MakeWildcard()); } } } diff --git a/explorer/interpreter/type_checker.cpp b/explorer/interpreter/type_checker.cpp index d5294912a0b2..4b781c27c6e6 100644 --- a/explorer/interpreter/type_checker.cpp +++ b/explorer/interpreter/type_checker.cpp @@ -4055,11 +4055,9 @@ auto TypeChecker::TypeCheckPattern( } case PatternKind::AlternativePattern: { auto& alternative = cast(*p); - CARBON_RETURN_IF_ERROR( - TypeCheckExp(&alternative.choice_type(), impl_scope)); CARBON_ASSIGN_OR_RETURN( Nonnull type, - InterpExp(&alternative.choice_type(), arena_, trace_stream_)); + TypeCheckTypeExp(&alternative.choice_type(), impl_scope)); if (!isa(type)) { return ProgramError(alternative.source_loc()) << "alternative pattern does not name a choice type."; diff --git a/explorer/testdata/choice/mixed_arity.carbon b/explorer/testdata/choice/mixed_arity.carbon new file mode 100644 index 000000000000..6127df6e26c6 --- /dev/null +++ b/explorer/testdata/choice/mixed_arity.carbon @@ -0,0 +1,38 @@ +// 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: 25 + +package ExplorerTest api; + +class List { + choice Node { + Nil, + Cons(i32, Self*) + } + var node: Node; + + // Creates a list of `Cons(n, Cons(n - 1, ... Cons(1, Nil) ... ))`. + fn Make(n: i32) -> Self { + return { + .node = if n == 0 then Node.Nil else Node.Cons(n, heap.New(Make(n - 1))) + }; + } + + // Returns the sum of values in the list plus the value of `a`. + fn Sum[self: Self](a: i32) -> i32 { + match (self.node) { + case Node.Nil => { return a; } + case Node.Cons(b: i32, rest: Self*) => { return rest->Sum(a + b); } + } + } +} + +fn Main() -> i32 { + var l: List = List.Make(5); + return l.Sum(10); +}