mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 09:41:08 +01:00
Improve support for qualification conversions. (#5999)
* Treat `MaybeUnformed` and `partial` as qualifiers, like `const`. * Allow pointer conversions to add qualifiers. * Allow unsafe pointer conversions to remove qualifiers. * Allow conversions on non-reference expressions to drop `const`. * Allow unsafe conversions on any expression to drop `const`. * Allow unsafe conversions on non-initializing expressions to drop `partial`. For initializing expressions, we should initialize the vptr when dropping `partial`; this is not yet supported so we reject. * Allow conversions on reference expressions to add `MaybeUnformed`. * Allow unsafe conversions on reference expressions to drop `MaybeUnformed`. For non-reference expressions, additional work is required, because the value / initializing representation may not match between `T` and `MaybeUnformed(T)`, so those are rejected for now.
This commit is contained in:
+103
-33
@@ -31,6 +31,7 @@
|
||||
#include "toolchain/sem_ir/generic.h"
|
||||
#include "toolchain/sem_ir/ids.h"
|
||||
#include "toolchain/sem_ir/inst.h"
|
||||
#include "toolchain/sem_ir/type.h"
|
||||
#include "toolchain/sem_ir/typed_insts.h"
|
||||
|
||||
// TODO: This contains a lot of recursion. Consider removing it in order to
|
||||
@@ -767,6 +768,58 @@ static auto CanUseValueOfInitializer(const SemIR::File& sem_ir,
|
||||
return InitReprIsCopyOfValueRepr(sem_ir, type_id);
|
||||
}
|
||||
|
||||
// Determine whether the given set of qualifiers can be added by a conversion
|
||||
// of an expression of the given category.
|
||||
static auto CanAddQualifiers(SemIR::TypeQualifiers quals,
|
||||
SemIR::ExprCategory cat) -> bool {
|
||||
if (HasTypeQualifier(quals, SemIR::TypeQualifiers::MaybeUnformed) &&
|
||||
!SemIR::IsRefCategory(cat)) {
|
||||
// `MaybeUnformed(T)` may have a different value representation or
|
||||
// initializing representation from `T`, so only allow it to be added for a
|
||||
// reference expression.
|
||||
// TODO: We should allow converting an initializing expression of type `T`
|
||||
// to `MaybeUnformed(T)`. `PerformBuiltinConversion` will need to generate
|
||||
// an `InPlaceInit` instruction when needed.
|
||||
// NOLINTNEXTLINE(readability-simplify-boolean-expr)
|
||||
return false;
|
||||
}
|
||||
|
||||
// `const` and `partial` can always be added.
|
||||
return true;
|
||||
}
|
||||
|
||||
// Determine whether the given set of qualifiers can be removed by a conversion
|
||||
// of an expression of the given category.
|
||||
static auto CanRemoveQualifiers(SemIR::TypeQualifiers quals,
|
||||
SemIR::ExprCategory cat, bool allow_unsafe)
|
||||
-> bool {
|
||||
if (HasTypeQualifier(quals, SemIR::TypeQualifiers::Const) && !allow_unsafe &&
|
||||
SemIR::IsRefCategory(cat)) {
|
||||
// Removing `const` is an unsafe conversion for a reference expression.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (HasTypeQualifier(quals, SemIR::TypeQualifiers::Partial) &&
|
||||
(!allow_unsafe || cat == SemIR::ExprCategory::Initializing)) {
|
||||
// TODO: Allow removing `partial` for initializing expressions as a safe
|
||||
// conversion. `PerformBuiltinConversion` will need to initialize the vptr
|
||||
// as part of the conversion.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (HasTypeQualifier(quals, SemIR::TypeQualifiers::MaybeUnformed) &&
|
||||
(!allow_unsafe || !SemIR::IsRefCategory(cat))) {
|
||||
// As an unsafe conversion, `MaybeUnformed` can be removed from a reference
|
||||
// expression.
|
||||
// TODO: We should allow this for any kind of expression, and convert the
|
||||
// result as needed if the representation of `T` differs from that of
|
||||
// `MaybeUnformed(T)`.
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static auto DiagnoseConversionFailureToConstraintValue(
|
||||
Context& context, SemIR::LocId loc_id, SemIR::InstId expr_id,
|
||||
SemIR::TypeId target_type_id) -> void {
|
||||
@@ -914,24 +967,32 @@ static auto PerformBuiltinConversion(
|
||||
}
|
||||
}
|
||||
|
||||
// T explicitly converts to U if T is compatible with U.
|
||||
// T explicitly converts to U if T is compatible with U, and we're allowed to
|
||||
// remove / add any qualifiers that differ.
|
||||
if (target.is_explicit_as() && target.type_id != value_type_id) {
|
||||
auto target_foundation_id =
|
||||
context.types().GetTransitiveAdaptedType(target.type_id);
|
||||
auto value_foundation_id =
|
||||
context.types().GetTransitiveAdaptedType(value_type_id);
|
||||
auto [target_foundation_id, target_quals] =
|
||||
context.types().GetTransitiveUnqualifiedAdaptedType(target.type_id);
|
||||
auto [value_foundation_id, value_quals] =
|
||||
context.types().GetTransitiveUnqualifiedAdaptedType(value_type_id);
|
||||
if (target_foundation_id == value_foundation_id) {
|
||||
// For a struct or tuple literal, perform a category conversion if
|
||||
// necessary.
|
||||
if (SemIR::GetExprCategory(context.sem_ir(), value_id) ==
|
||||
SemIR::ExprCategory::Mixed) {
|
||||
value_id = PerformBuiltinConversion(context, loc_id, value_id,
|
||||
{.kind = ConversionTarget::Value,
|
||||
.type_id = value_type_id,
|
||||
.diagnose = target.diagnose});
|
||||
auto category = SemIR::GetExprCategory(context.sem_ir(), value_id);
|
||||
if (CanAddQualifiers(target_quals & ~value_quals, category) &&
|
||||
CanRemoveQualifiers(
|
||||
value_quals & ~target_quals, category,
|
||||
target.kind == ConversionTarget::ExplicitUnsafeAs)) {
|
||||
// For a struct or tuple literal, perform a category conversion if
|
||||
// necessary.
|
||||
if (category == SemIR::ExprCategory::Mixed) {
|
||||
value_id = PerformBuiltinConversion(context, loc_id, value_id,
|
||||
{.kind = ConversionTarget::Value,
|
||||
.type_id = value_type_id,
|
||||
.diagnose = target.diagnose});
|
||||
}
|
||||
|
||||
return AddInst<SemIR::AsCompatible>(
|
||||
context, loc_id,
|
||||
{.type_id = target.type_id, .source_id = value_id});
|
||||
}
|
||||
return AddInst<SemIR::AsCompatible>(
|
||||
context, loc_id, {.type_id = target.type_id, .source_id = value_id});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -996,19 +1057,23 @@ static auto PerformBuiltinConversion(
|
||||
}
|
||||
}
|
||||
|
||||
// A pointer T* converts to [const] U* if T is the same as U, or is a class
|
||||
// derived from U.
|
||||
// A pointer T* converts to [qualified] U* if T is the same as U, or is a
|
||||
// class derived from U.
|
||||
if (auto target_pointer_type = target_type_inst.TryAs<SemIR::PointerType>()) {
|
||||
if (auto src_pointer_type =
|
||||
sem_ir.types().TryGetAs<SemIR::PointerType>(value_type_id)) {
|
||||
auto target_pointee_id = context.types().GetTypeIdForTypeInstId(
|
||||
target_pointer_type->pointee_id);
|
||||
auto src_pointee_id =
|
||||
context.types().GetTypeIdForTypeInstId(src_pointer_type->pointee_id);
|
||||
// Try to complete the pointee types so that we can walk through adapters
|
||||
// to their adapted types.
|
||||
TryToCompleteType(context, target_pointee_id, loc_id);
|
||||
TryToCompleteType(context, src_pointee_id, loc_id);
|
||||
auto [unqual_target_pointee_type_id, target_quals] =
|
||||
sem_ir.types().GetUnqualifiedTypeAndQualifiers(
|
||||
context.types().GetTypeIdForTypeInstId(
|
||||
target_pointer_type->pointee_id));
|
||||
sem_ir.types().GetTransitiveUnqualifiedAdaptedType(target_pointee_id);
|
||||
auto [unqual_src_pointee_type_id, src_quals] =
|
||||
sem_ir.types().GetUnqualifiedTypeAndQualifiers(
|
||||
context.types().GetTypeIdForTypeInstId(
|
||||
src_pointer_type->pointee_id));
|
||||
sem_ir.types().GetTransitiveUnqualifiedAdaptedType(src_pointee_id);
|
||||
|
||||
// If the qualifiers are incompatible, we can't perform a conversion,
|
||||
// except with `unsafe as`.
|
||||
@@ -1366,25 +1431,30 @@ auto Convert(Context& context, SemIR::LocId loc_id, SemIR::InstId expr_id,
|
||||
if (!target.diagnose) {
|
||||
return context.emitter().BuildSuppressed();
|
||||
}
|
||||
int target_kind_for_diag =
|
||||
target.kind == ConversionTarget::ExplicitAs ? 1
|
||||
: target.kind == ConversionTarget::ExplicitUnsafeAs ? 2
|
||||
: 0;
|
||||
if (target.type_id == SemIR::TypeType::TypeId ||
|
||||
sem_ir.types().Is<SemIR::FacetType>(target.type_id)) {
|
||||
CARBON_DIAGNOSTIC(
|
||||
ConversionFailureNonTypeToFacet, Error,
|
||||
"cannot{0:| implicitly} convert non-type value of type {1} "
|
||||
"{2:to|into type implementing} {3}{0: with `as`|}",
|
||||
Diagnostics::BoolAsSelect, TypeOfInstId, Diagnostics::BoolAsSelect,
|
||||
"cannot{0:=0: implicitly|:} convert non-type value of type {1} "
|
||||
"{2:to|into type implementing} {3}"
|
||||
"{0:=1: with `as`|=2: with `unsafe as`|:}",
|
||||
Diagnostics::IntAsSelect, TypeOfInstId, Diagnostics::BoolAsSelect,
|
||||
SemIR::TypeId);
|
||||
return context.emitter().Build(
|
||||
loc_id, ConversionFailureNonTypeToFacet, target.is_explicit_as(),
|
||||
loc_id, ConversionFailureNonTypeToFacet, target_kind_for_diag,
|
||||
expr_id, target.type_id == SemIR::TypeType::TypeId, target.type_id);
|
||||
} else {
|
||||
CARBON_DIAGNOSTIC(ConversionFailure, Error,
|
||||
"cannot{0:| implicitly} convert expression of type "
|
||||
"{1} to {2}{0: with `as`|}",
|
||||
Diagnostics::BoolAsSelect, TypeOfInstId,
|
||||
SemIR::TypeId);
|
||||
CARBON_DIAGNOSTIC(
|
||||
ConversionFailure, Error,
|
||||
"cannot{0:=0: implicitly|:} convert expression of type "
|
||||
"{1} to {2}{0:=1: with `as`|=2: with `unsafe as`|:}",
|
||||
Diagnostics::IntAsSelect, TypeOfInstId, SemIR::TypeId);
|
||||
return context.emitter().Build(loc_id, ConversionFailure,
|
||||
target.is_explicit_as(), expr_id,
|
||||
target_kind_for_diag, expr_id,
|
||||
target.type_id);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "toolchain/sem_ir/ids.h"
|
||||
#include "toolchain/sem_ir/import_ir.h"
|
||||
#include "toolchain/sem_ir/inst.h"
|
||||
#include "toolchain/sem_ir/inst_categories.h"
|
||||
#include "toolchain/sem_ir/inst_kind.h"
|
||||
#include "toolchain/sem_ir/type_info.h"
|
||||
#include "toolchain/sem_ir/typed_insts.h"
|
||||
@@ -1823,14 +1824,16 @@ static auto TryResolveTypedInst(ImportRefResolver& resolver,
|
||||
.object_repr_type_inst_id = object_repr_type_inst_id});
|
||||
}
|
||||
|
||||
static auto TryResolveTypedInst(ImportRefResolver& resolver,
|
||||
SemIR::ConstType inst) -> ResolveResult {
|
||||
template <typename InstT>
|
||||
requires SemIR::Internal::HasInstCategory<SemIR::AnyQualifiedType, InstT>
|
||||
static auto TryResolveTypedInst(ImportRefResolver& resolver, InstT inst)
|
||||
-> ResolveResult {
|
||||
CARBON_CHECK(inst.type_id == SemIR::TypeType::TypeId);
|
||||
auto inner_id = GetLocalTypeInstId(resolver, inst.inner_id);
|
||||
if (resolver.HasNewWork()) {
|
||||
return ResolveResult::Retry();
|
||||
}
|
||||
return ResolveAsDeduplicated<SemIR::ConstType>(
|
||||
return ResolveAsDeduplicated<InstT>(
|
||||
resolver, {.type_id = SemIR::TypeType::TypeId, .inner_id = inner_id});
|
||||
}
|
||||
|
||||
@@ -3183,12 +3186,18 @@ static auto TryResolveInstCanonical(ImportRefResolver& resolver,
|
||||
case CARBON_KIND(SemIR::IntType inst): {
|
||||
return TryResolveTypedInst(resolver, inst);
|
||||
}
|
||||
case CARBON_KIND(SemIR::MaybeUnformedType inst): {
|
||||
return TryResolveTypedInst(resolver, inst);
|
||||
}
|
||||
case CARBON_KIND(SemIR::Namespace inst): {
|
||||
return TryResolveTypedInst(resolver, inst, inst_id);
|
||||
}
|
||||
case CARBON_KIND(SemIR::OutParamPattern inst): {
|
||||
return TryResolveTypedInst(resolver, inst, inst_id);
|
||||
}
|
||||
case CARBON_KIND(SemIR::PartialType inst): {
|
||||
return TryResolveTypedInst(resolver, inst);
|
||||
}
|
||||
case CARBON_KIND(SemIR::PatternType inst): {
|
||||
return TryResolveTypedInst(resolver, inst);
|
||||
}
|
||||
|
||||
+303
@@ -0,0 +1,303 @@
|
||||
// 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
|
||||
//
|
||||
// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/convert.carbon
|
||||
//
|
||||
// AUTOUPDATE
|
||||
// TIP: To test this file alone, run:
|
||||
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/as/const.carbon
|
||||
// TIP: To dump output, run:
|
||||
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/as/const.carbon
|
||||
|
||||
// --- add_const.carbon
|
||||
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
class X {}
|
||||
|
||||
fn Init() -> X;
|
||||
let value: X = Init();
|
||||
var reference: X;
|
||||
let ptr: X* = &reference;
|
||||
|
||||
fn Use() {
|
||||
// TODO: Should some of these be valid without the `as`?
|
||||
//@dump-sem-ir-begin
|
||||
var i: const X = Init() as const X;
|
||||
let v: const X = value as const X;
|
||||
let a: const X* = &(reference as const X);
|
||||
let b: const X* = ptr as const X*;
|
||||
//@dump-sem-ir-end
|
||||
}
|
||||
|
||||
// --- remove_const.carbon
|
||||
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
class X {}
|
||||
|
||||
fn Init() -> const X;
|
||||
let value: const X = Init();
|
||||
|
||||
fn Use() {
|
||||
// TODO: Should some of these be valid without the `as`?
|
||||
//@dump-sem-ir-begin
|
||||
var i: X = Init() as X;
|
||||
let v: X = value as X;
|
||||
//@dump-sem-ir-end
|
||||
}
|
||||
|
||||
// --- fail_cannot_remove_const.carbon
|
||||
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
class X {}
|
||||
|
||||
var reference: const X;
|
||||
let ptr: const X* = &reference;
|
||||
|
||||
fn Use() {
|
||||
// CHECK:STDERR: fail_cannot_remove_const.carbon:[[@LINE+7]]:17: error: cannot convert expression of type `const X` to `X` with `as` [ConversionFailure]
|
||||
// CHECK:STDERR: let a: X* = &(reference as X);
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~
|
||||
// CHECK:STDERR: fail_cannot_remove_const.carbon:[[@LINE+4]]:17: note: type `const X` does not implement interface `Core.As(X)` [MissingImplInMemberAccessNote]
|
||||
// CHECK:STDERR: let a: X* = &(reference as X);
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
let a: X* = &(reference as X);
|
||||
// CHECK:STDERR: fail_cannot_remove_const.carbon:[[@LINE+7]]:15: error: cannot convert expression of type `const X*` to `X*` with `as` [ConversionFailure]
|
||||
// CHECK:STDERR: let b: X* = ptr as X*;
|
||||
// CHECK:STDERR: ^~~~~~~~~
|
||||
// CHECK:STDERR: fail_cannot_remove_const.carbon:[[@LINE+4]]:15: note: type `const X*` does not implement interface `Core.As(X*)` [MissingImplInMemberAccessNote]
|
||||
// CHECK:STDERR: let b: X* = ptr as X*;
|
||||
// CHECK:STDERR: ^~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
let b: X* = ptr as X*;
|
||||
}
|
||||
|
||||
// --- unsafe_remove_const.carbon
|
||||
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
class X {}
|
||||
|
||||
var reference: const X;
|
||||
let ptr: const X* = &reference;
|
||||
|
||||
fn Use() {
|
||||
//@dump-sem-ir-begin
|
||||
let a: X* = &(reference unsafe as X);
|
||||
let b: X* = ptr unsafe as X*;
|
||||
//@dump-sem-ir-end
|
||||
}
|
||||
|
||||
// CHECK:STDOUT: --- add_const.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %X: type = class_type @X [concrete]
|
||||
// CHECK:STDOUT: %ptr.d17: type = ptr_type %X [concrete]
|
||||
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
|
||||
// CHECK:STDOUT: %Init.type: type = fn_type @Init [concrete]
|
||||
// CHECK:STDOUT: %Init: %Init.type = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %const: type = const_type %X [concrete]
|
||||
// CHECK:STDOUT: %pattern_type.d7f: type = pattern_type %const [concrete]
|
||||
// CHECK:STDOUT: %ptr.cbd: type = ptr_type %const [concrete]
|
||||
// CHECK:STDOUT: %pattern_type.855: type = pattern_type %ptr.cbd [concrete]
|
||||
// CHECK:STDOUT: %reference.var: ref %const = var file.%reference.var_patt [concrete]
|
||||
// CHECK:STDOUT: %addr.0c5: %ptr.cbd = addr_of %reference.var [concrete]
|
||||
// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.f3e: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%const) [concrete]
|
||||
// CHECK:STDOUT: %T.as.Destroy.impl.Op.4e8: %T.as.Destroy.impl.Op.type.f3e = struct_value () [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: imports {
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @Use() {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: name_binding_decl {
|
||||
// CHECK:STDOUT: %i.patt: %pattern_type.d7f = binding_pattern i [concrete]
|
||||
// CHECK:STDOUT: %i.var_patt: %pattern_type.d7f = var_pattern %i.patt [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %i.var: ref %const = var %i.var_patt
|
||||
// CHECK:STDOUT: %Init.ref: %Init.type = name_ref Init, file.%Init.decl [concrete = constants.%Init]
|
||||
// CHECK:STDOUT: %.loc14_3: ref %const = splice_block %i.var {}
|
||||
// CHECK:STDOUT: %Init.call: init %X = call %Init.ref() to %.loc14_3
|
||||
// CHECK:STDOUT: %X.ref.loc14_36: type = name_ref X, file.%X.decl [concrete = constants.%X]
|
||||
// CHECK:STDOUT: %const.loc14_30: type = const_type %X.ref.loc14_36 [concrete = constants.%const]
|
||||
// CHECK:STDOUT: %.loc14_27.1: init %const = as_compatible %Init.call
|
||||
// CHECK:STDOUT: %.loc14_27.2: init %const = converted %Init.call, %.loc14_27.1
|
||||
// CHECK:STDOUT: assign %i.var, %.loc14_27.2
|
||||
// CHECK:STDOUT: %.loc14_10: type = splice_block %const.loc14_10 [concrete = constants.%const] {
|
||||
// CHECK:STDOUT: %X.ref.loc14_16: type = name_ref X, file.%X.decl [concrete = constants.%X]
|
||||
// CHECK:STDOUT: %const.loc14_10: type = const_type %X.ref.loc14_16 [concrete = constants.%const]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %i: ref %const = bind_name i, %i.var
|
||||
// CHECK:STDOUT: name_binding_decl {
|
||||
// CHECK:STDOUT: %v.patt: %pattern_type.d7f = binding_pattern v [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %value.ref: %X = name_ref value, file.%value
|
||||
// CHECK:STDOUT: %X.ref.loc15_35: type = name_ref X, file.%X.decl [concrete = constants.%X]
|
||||
// CHECK:STDOUT: %const.loc15_29: type = const_type %X.ref.loc15_35 [concrete = constants.%const]
|
||||
// CHECK:STDOUT: %.loc15_26.1: %const = as_compatible %value.ref
|
||||
// CHECK:STDOUT: %.loc15_26.2: %const = converted %value.ref, %.loc15_26.1
|
||||
// CHECK:STDOUT: %.loc15_10: type = splice_block %const.loc15_10 [concrete = constants.%const] {
|
||||
// CHECK:STDOUT: %X.ref.loc15_16: type = name_ref X, file.%X.decl [concrete = constants.%X]
|
||||
// CHECK:STDOUT: %const.loc15_10: type = const_type %X.ref.loc15_16 [concrete = constants.%const]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %v: %const = bind_name v, %.loc15_26.2
|
||||
// CHECK:STDOUT: name_binding_decl {
|
||||
// CHECK:STDOUT: %a.patt: %pattern_type.855 = binding_pattern a [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %reference.ref: ref %X = name_ref reference, file.%reference [concrete = file.%reference.var]
|
||||
// CHECK:STDOUT: %X.ref.loc16_42: type = name_ref X, file.%X.decl [concrete = constants.%X]
|
||||
// CHECK:STDOUT: %const.loc16_36: type = const_type %X.ref.loc16_42 [concrete = constants.%const]
|
||||
// CHECK:STDOUT: %.loc16_33.1: ref %const = as_compatible %reference.ref [concrete = constants.%reference.var]
|
||||
// CHECK:STDOUT: %.loc16_33.2: ref %const = converted %reference.ref, %.loc16_33.1 [concrete = constants.%reference.var]
|
||||
// CHECK:STDOUT: %addr.loc16: %ptr.cbd = addr_of %.loc16_33.2 [concrete = constants.%addr.0c5]
|
||||
// CHECK:STDOUT: %.loc16_17: type = splice_block %ptr.loc16 [concrete = constants.%ptr.cbd] {
|
||||
// CHECK:STDOUT: %X.ref.loc16_16: type = name_ref X, file.%X.decl [concrete = constants.%X]
|
||||
// CHECK:STDOUT: %const.loc16_10: type = const_type %X.ref.loc16_16 [concrete = constants.%const]
|
||||
// CHECK:STDOUT: %ptr.loc16: type = ptr_type %const.loc16_10 [concrete = constants.%ptr.cbd]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %a: %ptr.cbd = bind_name a, %addr.loc16
|
||||
// CHECK:STDOUT: name_binding_decl {
|
||||
// CHECK:STDOUT: %b.patt: %pattern_type.855 = binding_pattern b [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %ptr.ref: %ptr.d17 = name_ref ptr, file.%ptr.loc9_5
|
||||
// CHECK:STDOUT: %X.ref.loc17_34: type = name_ref X, file.%X.decl [concrete = constants.%X]
|
||||
// CHECK:STDOUT: %const.loc17_28: type = const_type %X.ref.loc17_34 [concrete = constants.%const]
|
||||
// CHECK:STDOUT: %ptr.loc17_35: type = ptr_type %const.loc17_28 [concrete = constants.%ptr.cbd]
|
||||
// CHECK:STDOUT: %.loc17_25.1: %ptr.cbd = as_compatible %ptr.ref
|
||||
// CHECK:STDOUT: %.loc17_25.2: %ptr.cbd = converted %ptr.ref, %.loc17_25.1
|
||||
// CHECK:STDOUT: %.loc17_17: type = splice_block %ptr.loc17_17 [concrete = constants.%ptr.cbd] {
|
||||
// CHECK:STDOUT: %X.ref.loc17_16: type = name_ref X, file.%X.decl [concrete = constants.%X]
|
||||
// CHECK:STDOUT: %const.loc17_10: type = const_type %X.ref.loc17_16 [concrete = constants.%const]
|
||||
// CHECK:STDOUT: %ptr.loc17_17: type = ptr_type %const.loc17_10 [concrete = constants.%ptr.cbd]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %b: %ptr.cbd = bind_name b, %.loc17_25.2
|
||||
// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc14_3.1: <bound method> = bound_method %.loc14_3, constants.%T.as.Destroy.impl.Op.4e8
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: %bound_method.loc14_3.1: <bound method> = bound_method %.loc14_3, %T.as.Destroy.impl.Op.specific_fn.1
|
||||
// CHECK:STDOUT: %addr.loc14_3.1: %ptr.cbd = addr_of %.loc14_3
|
||||
// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc14_3.1: init %empty_tuple.type = call %bound_method.loc14_3.1(%addr.loc14_3.1)
|
||||
// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc14_3.2: <bound method> = bound_method %i.var, constants.%T.as.Destroy.impl.Op.4e8
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: %bound_method.loc14_3.2: <bound method> = bound_method %i.var, %T.as.Destroy.impl.Op.specific_fn.2
|
||||
// CHECK:STDOUT: %addr.loc14_3.2: %ptr.cbd = addr_of %i.var
|
||||
// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc14_3.2: init %empty_tuple.type = call %bound_method.loc14_3.2(%addr.loc14_3.2)
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @__global_init() {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- remove_const.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %X: type = class_type @X [concrete]
|
||||
// CHECK:STDOUT: %ptr.d17: type = ptr_type %X [concrete]
|
||||
// CHECK:STDOUT: %X.as.Destroy.impl.Op.type: type = fn_type @X.as.Destroy.impl.Op [concrete]
|
||||
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
|
||||
// CHECK:STDOUT: %X.as.Destroy.impl.Op: %X.as.Destroy.impl.Op.type = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %const: type = const_type %X [concrete]
|
||||
// CHECK:STDOUT: %Init.type: type = fn_type @Init [concrete]
|
||||
// CHECK:STDOUT: %Init: %Init.type = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %pattern_type.019: type = pattern_type %X [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: imports {
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @Use() {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: name_binding_decl {
|
||||
// CHECK:STDOUT: %i.patt: %pattern_type.019 = binding_pattern i [concrete]
|
||||
// CHECK:STDOUT: %i.var_patt: %pattern_type.019 = var_pattern %i.patt [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %i.var: ref %X = var %i.var_patt
|
||||
// CHECK:STDOUT: %Init.ref: %Init.type = name_ref Init, file.%Init.decl [concrete = constants.%Init]
|
||||
// CHECK:STDOUT: %.loc12_3: ref %X = splice_block %i.var {}
|
||||
// CHECK:STDOUT: %Init.call: init %const = call %Init.ref() to %.loc12_3
|
||||
// CHECK:STDOUT: %X.ref.loc12_24: type = name_ref X, file.%X.decl [concrete = constants.%X]
|
||||
// CHECK:STDOUT: %.loc12_21.1: init %X = as_compatible %Init.call
|
||||
// CHECK:STDOUT: %.loc12_21.2: init %X = converted %Init.call, %.loc12_21.1
|
||||
// CHECK:STDOUT: assign %i.var, %.loc12_21.2
|
||||
// CHECK:STDOUT: %X.ref.loc12_10: type = name_ref X, file.%X.decl [concrete = constants.%X]
|
||||
// CHECK:STDOUT: %i: ref %X = bind_name i, %i.var
|
||||
// CHECK:STDOUT: name_binding_decl {
|
||||
// CHECK:STDOUT: %v.patt: %pattern_type.019 = binding_pattern v [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %value.ref: %const = name_ref value, file.%value
|
||||
// CHECK:STDOUT: %X.ref.loc13_23: type = name_ref X, file.%X.decl [concrete = constants.%X]
|
||||
// CHECK:STDOUT: %.loc13_20.1: %X = as_compatible %value.ref
|
||||
// CHECK:STDOUT: %.loc13_20.2: %X = converted %value.ref, %.loc13_20.1
|
||||
// CHECK:STDOUT: %X.ref.loc13_10: type = name_ref X, file.%X.decl [concrete = constants.%X]
|
||||
// CHECK:STDOUT: %v: %X = bind_name v, %.loc13_20.2
|
||||
// CHECK:STDOUT: %X.as.Destroy.impl.Op.bound.loc12_3.1: <bound method> = bound_method %.loc12_3, constants.%X.as.Destroy.impl.Op
|
||||
// CHECK:STDOUT: %addr.loc12_3.1: %ptr.d17 = addr_of %.loc12_3
|
||||
// CHECK:STDOUT: %X.as.Destroy.impl.Op.call.loc12_3.1: init %empty_tuple.type = call %X.as.Destroy.impl.Op.bound.loc12_3.1(%addr.loc12_3.1)
|
||||
// CHECK:STDOUT: %X.as.Destroy.impl.Op.bound.loc12_3.2: <bound method> = bound_method %i.var, constants.%X.as.Destroy.impl.Op
|
||||
// CHECK:STDOUT: %addr.loc12_3.2: %ptr.d17 = addr_of %i.var
|
||||
// CHECK:STDOUT: %X.as.Destroy.impl.Op.call.loc12_3.2: init %empty_tuple.type = call %X.as.Destroy.impl.Op.bound.loc12_3.2(%addr.loc12_3.2)
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @__global_init() {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- unsafe_remove_const.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %X: type = class_type @X [concrete]
|
||||
// CHECK:STDOUT: %ptr.d17: type = ptr_type %X [concrete]
|
||||
// CHECK:STDOUT: %pattern_type.1c6: type = pattern_type %ptr.d17 [concrete]
|
||||
// CHECK:STDOUT: %const: type = const_type %X [concrete]
|
||||
// CHECK:STDOUT: %ptr.cbd: type = ptr_type %const [concrete]
|
||||
// CHECK:STDOUT: %reference.var: ref %X = var file.%reference.var_patt [concrete]
|
||||
// CHECK:STDOUT: %addr.373: %ptr.d17 = addr_of %reference.var [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: imports {
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @Use() {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: name_binding_decl {
|
||||
// CHECK:STDOUT: %a.patt: %pattern_type.1c6 = binding_pattern a [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %reference.ref: ref %const = name_ref reference, file.%reference [concrete = file.%reference.var]
|
||||
// CHECK:STDOUT: %X.ref.loc11_37: type = name_ref X, file.%X.decl [concrete = constants.%X]
|
||||
// CHECK:STDOUT: %.loc11_34.1: ref %X = as_compatible %reference.ref [concrete = constants.%reference.var]
|
||||
// CHECK:STDOUT: %.loc11_34.2: ref %X = converted %reference.ref, %.loc11_34.1 [concrete = constants.%reference.var]
|
||||
// CHECK:STDOUT: %addr: %ptr.d17 = addr_of %.loc11_34.2 [concrete = constants.%addr.373]
|
||||
// CHECK:STDOUT: %.loc11_11: type = splice_block %ptr.loc11 [concrete = constants.%ptr.d17] {
|
||||
// CHECK:STDOUT: %X.ref.loc11_10: type = name_ref X, file.%X.decl [concrete = constants.%X]
|
||||
// CHECK:STDOUT: %ptr.loc11: type = ptr_type %X.ref.loc11_10 [concrete = constants.%ptr.d17]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %a: %ptr.d17 = bind_name a, %addr
|
||||
// CHECK:STDOUT: name_binding_decl {
|
||||
// CHECK:STDOUT: %b.patt: %pattern_type.1c6 = binding_pattern b [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %ptr.ref: %ptr.cbd = name_ref ptr, file.%ptr.loc7_5
|
||||
// CHECK:STDOUT: %X.ref.loc12_29: type = name_ref X, file.%X.decl [concrete = constants.%X]
|
||||
// CHECK:STDOUT: %ptr.loc12_30: type = ptr_type %X.ref.loc12_29 [concrete = constants.%ptr.d17]
|
||||
// CHECK:STDOUT: %.loc12_26.1: %ptr.d17 = as_compatible %ptr.ref
|
||||
// CHECK:STDOUT: %.loc12_26.2: %ptr.d17 = converted %ptr.ref, %.loc12_26.1
|
||||
// CHECK:STDOUT: %.loc12_11: type = splice_block %ptr.loc12_11 [concrete = constants.%ptr.d17] {
|
||||
// CHECK:STDOUT: %X.ref.loc12_10: type = name_ref X, file.%X.decl [concrete = constants.%X]
|
||||
// CHECK:STDOUT: %ptr.loc12_11: type = ptr_type %X.ref.loc12_10 [concrete = constants.%ptr.d17]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %b: %ptr.d17 = bind_name b, %.loc12_26.2
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @__global_init() {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
+366
@@ -0,0 +1,366 @@
|
||||
// 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
|
||||
//
|
||||
// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/unformed.carbon
|
||||
//
|
||||
// AUTOUPDATE
|
||||
// TIP: To test this file alone, run:
|
||||
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/as/maybe_unformed.carbon
|
||||
// TIP: To dump output, run:
|
||||
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/as/maybe_unformed.carbon
|
||||
|
||||
// --- add_unformed.carbon
|
||||
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
class X {}
|
||||
|
||||
var reference: X;
|
||||
let ptr: X* = &reference;
|
||||
|
||||
fn Use() {
|
||||
// TODO: Should some of these be valid without the `as`?
|
||||
//@dump-sem-ir-begin
|
||||
let a: Core.MaybeUnformed(X)* = &(reference as Core.MaybeUnformed(X));
|
||||
let b: Core.MaybeUnformed(X)* = ptr as Core.MaybeUnformed(X)*;
|
||||
//@dump-sem-ir-end
|
||||
}
|
||||
|
||||
// --- fail_todo_add_unformed_nonref.carbon
|
||||
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
class X {}
|
||||
|
||||
fn Init() -> X;
|
||||
let value: X = Init();
|
||||
|
||||
fn Use() {
|
||||
// TODO: These should probably be valid.
|
||||
//@dump-sem-ir-begin
|
||||
// CHECK:STDERR: fail_todo_add_unformed_nonref.carbon:[[@LINE+7]]:34: error: cannot convert expression of type `X` to `Core.MaybeUnformed(X)` with `as` [ConversionFailure]
|
||||
// CHECK:STDERR: var i: Core.MaybeUnformed(X) = Init() as Core.MaybeUnformed(X);
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// CHECK:STDERR: fail_todo_add_unformed_nonref.carbon:[[@LINE+4]]:34: note: type `X` does not implement interface `Core.As(Core.MaybeUnformed(X))` [MissingImplInMemberAccessNote]
|
||||
// CHECK:STDERR: var i: Core.MaybeUnformed(X) = Init() as Core.MaybeUnformed(X);
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
var i: Core.MaybeUnformed(X) = Init() as Core.MaybeUnformed(X);
|
||||
// CHECK:STDERR: fail_todo_add_unformed_nonref.carbon:[[@LINE+7]]:34: error: cannot convert expression of type `X` to `Core.MaybeUnformed(X)` with `as` [ConversionFailure]
|
||||
// CHECK:STDERR: let v: Core.MaybeUnformed(X) = value as Core.MaybeUnformed(X);
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// CHECK:STDERR: fail_todo_add_unformed_nonref.carbon:[[@LINE+4]]:34: note: type `X` does not implement interface `Core.As(Core.MaybeUnformed(X))` [MissingImplInMemberAccessNote]
|
||||
// CHECK:STDERR: let v: Core.MaybeUnformed(X) = value as Core.MaybeUnformed(X);
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
let v: Core.MaybeUnformed(X) = value as Core.MaybeUnformed(X);
|
||||
//@dump-sem-ir-end
|
||||
}
|
||||
|
||||
// --- fail_cannot_remove_unformed.carbon
|
||||
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
class X {}
|
||||
|
||||
fn Init() -> Core.MaybeUnformed(X);
|
||||
let value: Core.MaybeUnformed(X) = Init();
|
||||
var reference: Core.MaybeUnformed(X);
|
||||
let ptr: Core.MaybeUnformed(X)* = &reference;
|
||||
|
||||
fn Use() {
|
||||
// CHECK:STDERR: fail_cannot_remove_unformed.carbon:[[@LINE+7]]:14: error: cannot convert expression of type `Core.MaybeUnformed(X)` to `X` with `as` [ConversionFailure]
|
||||
// CHECK:STDERR: var i: X = Init() as X;
|
||||
// CHECK:STDERR: ^~~~~~~~~~~
|
||||
// CHECK:STDERR: fail_cannot_remove_unformed.carbon:[[@LINE+4]]:14: note: type `Core.MaybeUnformed(X)` does not implement interface `Core.As(X)` [MissingImplInMemberAccessNote]
|
||||
// CHECK:STDERR: var i: X = Init() as X;
|
||||
// CHECK:STDERR: ^~~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
var i: X = Init() as X;
|
||||
// CHECK:STDERR: fail_cannot_remove_unformed.carbon:[[@LINE+7]]:14: error: cannot convert expression of type `Core.MaybeUnformed(X)` to `X` with `as` [ConversionFailure]
|
||||
// CHECK:STDERR: let v: X = value as X;
|
||||
// CHECK:STDERR: ^~~~~~~~~~
|
||||
// CHECK:STDERR: fail_cannot_remove_unformed.carbon:[[@LINE+4]]:14: note: type `Core.MaybeUnformed(X)` does not implement interface `Core.As(X)` [MissingImplInMemberAccessNote]
|
||||
// CHECK:STDERR: let v: X = value as X;
|
||||
// CHECK:STDERR: ^~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
let v: X = value as X;
|
||||
// CHECK:STDERR: fail_cannot_remove_unformed.carbon:[[@LINE+7]]:17: error: cannot convert expression of type `Core.MaybeUnformed(X)` to `X` with `as` [ConversionFailure]
|
||||
// CHECK:STDERR: let a: X* = &(reference as X);
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~
|
||||
// CHECK:STDERR: fail_cannot_remove_unformed.carbon:[[@LINE+4]]:17: note: type `Core.MaybeUnformed(X)` does not implement interface `Core.As(X)` [MissingImplInMemberAccessNote]
|
||||
// CHECK:STDERR: let a: X* = &(reference as X);
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
let a: X* = &(reference as X);
|
||||
// CHECK:STDERR: fail_cannot_remove_unformed.carbon:[[@LINE+7]]:15: error: cannot convert expression of type `Core.MaybeUnformed(X)*` to `X*` with `as` [ConversionFailure]
|
||||
// CHECK:STDERR: let b: X* = ptr as X*;
|
||||
// CHECK:STDERR: ^~~~~~~~~
|
||||
// CHECK:STDERR: fail_cannot_remove_unformed.carbon:[[@LINE+4]]:15: note: type `Core.MaybeUnformed(X)*` does not implement interface `Core.As(X*)` [MissingImplInMemberAccessNote]
|
||||
// CHECK:STDERR: let b: X* = ptr as X*;
|
||||
// CHECK:STDERR: ^~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
let b: X* = ptr as X*;
|
||||
}
|
||||
|
||||
// --- unsafe_remove_unformed.carbon
|
||||
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
class X {}
|
||||
|
||||
var reference: Core.MaybeUnformed(X);
|
||||
let ptr: Core.MaybeUnformed(X)* = &reference;
|
||||
|
||||
fn Use() {
|
||||
//@dump-sem-ir-begin
|
||||
let a: X* = &(reference unsafe as X);
|
||||
let b: X* = ptr unsafe as X*;
|
||||
//@dump-sem-ir-end
|
||||
}
|
||||
|
||||
// --- fail_todo_remove_unformed_unsafe_notref.carbon
|
||||
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
class X {}
|
||||
|
||||
fn Init() -> Core.MaybeUnformed(X);
|
||||
let value: Core.MaybeUnformed(X) = Init();
|
||||
|
||||
fn Use() {
|
||||
// TODO: These should probably be valid.
|
||||
// CHECK:STDERR: fail_todo_remove_unformed_unsafe_notref.carbon:[[@LINE+7]]:14: error: cannot convert expression of type `Core.MaybeUnformed(X)` to `X` with `unsafe as` [ConversionFailure]
|
||||
// CHECK:STDERR: var i: X = Init() unsafe as X;
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~
|
||||
// CHECK:STDERR: fail_todo_remove_unformed_unsafe_notref.carbon:[[@LINE+4]]:14: note: type `Core.MaybeUnformed(X)` does not implement interface `Core.UnsafeAs(X)` [MissingImplInMemberAccessNote]
|
||||
// CHECK:STDERR: var i: X = Init() unsafe as X;
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
var i: X = Init() unsafe as X;
|
||||
// CHECK:STDERR: fail_todo_remove_unformed_unsafe_notref.carbon:[[@LINE+7]]:14: error: cannot convert expression of type `Core.MaybeUnformed(X)` to `X` with `unsafe as` [ConversionFailure]
|
||||
// CHECK:STDERR: let v: X = value unsafe as X;
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~
|
||||
// CHECK:STDERR: fail_todo_remove_unformed_unsafe_notref.carbon:[[@LINE+4]]:14: note: type `Core.MaybeUnformed(X)` does not implement interface `Core.UnsafeAs(X)` [MissingImplInMemberAccessNote]
|
||||
// CHECK:STDERR: let v: X = value unsafe as X;
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
let v: X = value unsafe as X;
|
||||
}
|
||||
|
||||
// CHECK:STDOUT: --- add_unformed.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %X: type = class_type @X [concrete]
|
||||
// CHECK:STDOUT: %Destroy.type: type = facet_type <@Destroy> [concrete]
|
||||
// CHECK:STDOUT: %ptr.d17: type = ptr_type %X [concrete]
|
||||
// CHECK:STDOUT: %MaybeUnformed.type: type = generic_class_type @MaybeUnformed [concrete]
|
||||
// CHECK:STDOUT: %MaybeUnformed.generic: %MaybeUnformed.type = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %MaybeUnformed.275: type = class_type @MaybeUnformed, @MaybeUnformed(%X) [concrete]
|
||||
// CHECK:STDOUT: %ptr.58e: type = ptr_type %MaybeUnformed.275 [concrete]
|
||||
// CHECK:STDOUT: %pattern_type.460: type = pattern_type %ptr.58e [concrete]
|
||||
// CHECK:STDOUT: %reference.var: ref %MaybeUnformed.275 = var file.%reference.var_patt [concrete]
|
||||
// CHECK:STDOUT: %addr.10a: %ptr.58e = addr_of %reference.var [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: imports {
|
||||
// CHECK:STDOUT: %Core: <namespace> = namespace file.%Core.import, [concrete] {
|
||||
// CHECK:STDOUT: .Destroy = %Core.Destroy
|
||||
// CHECK:STDOUT: .MaybeUnformed = %Core.MaybeUnformed
|
||||
// CHECK:STDOUT: import Core//prelude
|
||||
// CHECK:STDOUT: import Core//prelude/...
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %Core.Destroy: type = import_ref Core//prelude/parts/destroy, Destroy, loaded [concrete = constants.%Destroy.type]
|
||||
// CHECK:STDOUT: %Core.MaybeUnformed: %MaybeUnformed.type = import_ref Core//prelude/parts/maybe_unformed, MaybeUnformed, loaded [concrete = constants.%MaybeUnformed.generic]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @Use() {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: name_binding_decl {
|
||||
// CHECK:STDOUT: %a.patt: %pattern_type.460 = binding_pattern a [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %reference.ref: ref %X = name_ref reference, file.%reference [concrete = file.%reference.var]
|
||||
// CHECK:STDOUT: %Core.ref.loc12_50: <namespace> = name_ref Core, imports.%Core [concrete = imports.%Core]
|
||||
// CHECK:STDOUT: %MaybeUnformed.ref.loc12_54: %MaybeUnformed.type = name_ref MaybeUnformed, imports.%Core.MaybeUnformed [concrete = constants.%MaybeUnformed.generic]
|
||||
// CHECK:STDOUT: %X.ref.loc12_69: type = name_ref X, file.%X.decl [concrete = constants.%X]
|
||||
// CHECK:STDOUT: %MaybeUnformed.loc12_70: type = class_type @MaybeUnformed, @MaybeUnformed(constants.%X) [concrete = constants.%MaybeUnformed.275]
|
||||
// CHECK:STDOUT: %.loc12_47.1: ref %MaybeUnformed.275 = as_compatible %reference.ref [concrete = constants.%reference.var]
|
||||
// CHECK:STDOUT: %.loc12_47.2: ref %MaybeUnformed.275 = converted %reference.ref, %.loc12_47.1 [concrete = constants.%reference.var]
|
||||
// CHECK:STDOUT: %addr: %ptr.58e = addr_of %.loc12_47.2 [concrete = constants.%addr.10a]
|
||||
// CHECK:STDOUT: %.loc12_31: type = splice_block %ptr.loc12 [concrete = constants.%ptr.58e] {
|
||||
// CHECK:STDOUT: %Core.ref.loc12_10: <namespace> = name_ref Core, imports.%Core [concrete = imports.%Core]
|
||||
// CHECK:STDOUT: %MaybeUnformed.ref.loc12_14: %MaybeUnformed.type = name_ref MaybeUnformed, imports.%Core.MaybeUnformed [concrete = constants.%MaybeUnformed.generic]
|
||||
// CHECK:STDOUT: %X.ref.loc12_29: type = name_ref X, file.%X.decl [concrete = constants.%X]
|
||||
// CHECK:STDOUT: %MaybeUnformed.loc12_30: type = class_type @MaybeUnformed, @MaybeUnformed(constants.%X) [concrete = constants.%MaybeUnformed.275]
|
||||
// CHECK:STDOUT: %ptr.loc12: type = ptr_type %MaybeUnformed.loc12_30 [concrete = constants.%ptr.58e]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %a: %ptr.58e = bind_name a, %addr
|
||||
// CHECK:STDOUT: name_binding_decl {
|
||||
// CHECK:STDOUT: %b.patt: %pattern_type.460 = binding_pattern b [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %ptr.ref: %ptr.d17 = name_ref ptr, file.%ptr.loc7_5
|
||||
// CHECK:STDOUT: %Core.ref.loc13_42: <namespace> = name_ref Core, imports.%Core [concrete = imports.%Core]
|
||||
// CHECK:STDOUT: %MaybeUnformed.ref.loc13_46: %MaybeUnformed.type = name_ref MaybeUnformed, imports.%Core.MaybeUnformed [concrete = constants.%MaybeUnformed.generic]
|
||||
// CHECK:STDOUT: %X.ref.loc13_61: type = name_ref X, file.%X.decl [concrete = constants.%X]
|
||||
// CHECK:STDOUT: %MaybeUnformed.loc13_62: type = class_type @MaybeUnformed, @MaybeUnformed(constants.%X) [concrete = constants.%MaybeUnformed.275]
|
||||
// CHECK:STDOUT: %ptr.loc13_63: type = ptr_type %MaybeUnformed.loc13_62 [concrete = constants.%ptr.58e]
|
||||
// CHECK:STDOUT: %.loc13_39.1: %ptr.58e = as_compatible %ptr.ref
|
||||
// CHECK:STDOUT: %.loc13_39.2: %ptr.58e = converted %ptr.ref, %.loc13_39.1
|
||||
// CHECK:STDOUT: %.loc13_31: type = splice_block %ptr.loc13_31 [concrete = constants.%ptr.58e] {
|
||||
// CHECK:STDOUT: %Core.ref.loc13_10: <namespace> = name_ref Core, imports.%Core [concrete = imports.%Core]
|
||||
// CHECK:STDOUT: %MaybeUnformed.ref.loc13_14: %MaybeUnformed.type = name_ref MaybeUnformed, imports.%Core.MaybeUnformed [concrete = constants.%MaybeUnformed.generic]
|
||||
// CHECK:STDOUT: %X.ref.loc13_29: type = name_ref X, file.%X.decl [concrete = constants.%X]
|
||||
// CHECK:STDOUT: %MaybeUnformed.loc13_30: type = class_type @MaybeUnformed, @MaybeUnformed(constants.%X) [concrete = constants.%MaybeUnformed.275]
|
||||
// CHECK:STDOUT: %ptr.loc13_31: type = ptr_type %MaybeUnformed.loc13_30 [concrete = constants.%ptr.58e]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %b: %ptr.58e = bind_name b, %.loc13_39.2
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @__global_init() {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- fail_todo_add_unformed_nonref.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %X: type = class_type @X [concrete]
|
||||
// CHECK:STDOUT: %Destroy.type: type = facet_type <@Destroy> [concrete]
|
||||
// CHECK:STDOUT: %ptr.d17: type = ptr_type %X [concrete]
|
||||
// CHECK:STDOUT: %X.as.Destroy.impl.Op.type: type = fn_type @X.as.Destroy.impl.Op [concrete]
|
||||
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
|
||||
// CHECK:STDOUT: %X.as.Destroy.impl.Op: %X.as.Destroy.impl.Op.type = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %Init.type: type = fn_type @Init [concrete]
|
||||
// CHECK:STDOUT: %Init: %Init.type = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %MaybeUnformed.type: type = generic_class_type @MaybeUnformed [concrete]
|
||||
// CHECK:STDOUT: %MaybeUnformed.generic: %MaybeUnformed.type = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %MaybeUnformed.275: type = class_type @MaybeUnformed, @MaybeUnformed(%X) [concrete]
|
||||
// CHECK:STDOUT: %pattern_type.eb8: type = pattern_type %MaybeUnformed.275 [concrete]
|
||||
// CHECK:STDOUT: %As.type.90f: type = generic_interface_type @As [concrete]
|
||||
// CHECK:STDOUT: %As.generic: %As.type.90f = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %MaybeUnformed.as.Destroy.impl.Op.type.3bf: type = fn_type @MaybeUnformed.as.Destroy.impl.Op, @MaybeUnformed.as.Destroy.impl(%X) [concrete]
|
||||
// CHECK:STDOUT: %MaybeUnformed.as.Destroy.impl.Op.b85: %MaybeUnformed.as.Destroy.impl.Op.type.3bf = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %ptr.58e: type = ptr_type %MaybeUnformed.275 [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: imports {
|
||||
// CHECK:STDOUT: %Core: <namespace> = namespace file.%Core.import, [concrete] {
|
||||
// CHECK:STDOUT: .Destroy = %Core.Destroy
|
||||
// CHECK:STDOUT: .MaybeUnformed = %Core.MaybeUnformed
|
||||
// CHECK:STDOUT: .As = %Core.As
|
||||
// CHECK:STDOUT: import Core//prelude
|
||||
// CHECK:STDOUT: import Core//prelude/...
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %Core.Destroy: type = import_ref Core//prelude/parts/destroy, Destroy, loaded [concrete = constants.%Destroy.type]
|
||||
// CHECK:STDOUT: %Core.MaybeUnformed: %MaybeUnformed.type = import_ref Core//prelude/parts/maybe_unformed, MaybeUnformed, loaded [concrete = constants.%MaybeUnformed.generic]
|
||||
// CHECK:STDOUT: %Core.As: %As.type.90f = import_ref Core//prelude/parts/as, As, loaded [concrete = constants.%As.generic]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @Use() {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: name_binding_decl {
|
||||
// CHECK:STDOUT: %i.patt: %pattern_type.eb8 = binding_pattern i [concrete]
|
||||
// CHECK:STDOUT: %i.var_patt: %pattern_type.eb8 = var_pattern %i.patt [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %i.var: ref %MaybeUnformed.275 = var %i.var_patt
|
||||
// CHECK:STDOUT: %Init.ref: %Init.type = name_ref Init, file.%Init.decl [concrete = constants.%Init]
|
||||
// CHECK:STDOUT: %.loc19_39: ref %X = temporary_storage
|
||||
// CHECK:STDOUT: %Init.call: init %X = call %Init.ref() to %.loc19_39
|
||||
// CHECK:STDOUT: %Core.ref.loc19_44: <namespace> = name_ref Core, imports.%Core [concrete = imports.%Core]
|
||||
// CHECK:STDOUT: %MaybeUnformed.ref.loc19_48: %MaybeUnformed.type = name_ref MaybeUnformed, imports.%Core.MaybeUnformed [concrete = constants.%MaybeUnformed.generic]
|
||||
// CHECK:STDOUT: %X.ref.loc19_63: type = name_ref X, file.%X.decl [concrete = constants.%X]
|
||||
// CHECK:STDOUT: %MaybeUnformed.loc19_64: type = class_type @MaybeUnformed, @MaybeUnformed(constants.%X) [concrete = constants.%MaybeUnformed.275]
|
||||
// CHECK:STDOUT: %.loc19_41: %MaybeUnformed.275 = converted %Init.call, <error> [concrete = <error>]
|
||||
// CHECK:STDOUT: assign %i.var, <error>
|
||||
// CHECK:STDOUT: %.loc19_30: type = splice_block %MaybeUnformed.loc19_30 [concrete = constants.%MaybeUnformed.275] {
|
||||
// CHECK:STDOUT: %Core.ref.loc19_10: <namespace> = name_ref Core, imports.%Core [concrete = imports.%Core]
|
||||
// CHECK:STDOUT: %MaybeUnformed.ref.loc19_14: %MaybeUnformed.type = name_ref MaybeUnformed, imports.%Core.MaybeUnformed [concrete = constants.%MaybeUnformed.generic]
|
||||
// CHECK:STDOUT: %X.ref.loc19_29: type = name_ref X, file.%X.decl [concrete = constants.%X]
|
||||
// CHECK:STDOUT: %MaybeUnformed.loc19_30: type = class_type @MaybeUnformed, @MaybeUnformed(constants.%X) [concrete = constants.%MaybeUnformed.275]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %i: ref %MaybeUnformed.275 = bind_name i, %i.var
|
||||
// CHECK:STDOUT: name_binding_decl {
|
||||
// CHECK:STDOUT: %v.patt: %pattern_type.eb8 = binding_pattern v [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %value.ref: %X = name_ref value, file.%value
|
||||
// CHECK:STDOUT: %Core.ref.loc27_43: <namespace> = name_ref Core, imports.%Core [concrete = imports.%Core]
|
||||
// CHECK:STDOUT: %MaybeUnformed.ref.loc27_47: %MaybeUnformed.type = name_ref MaybeUnformed, imports.%Core.MaybeUnformed [concrete = constants.%MaybeUnformed.generic]
|
||||
// CHECK:STDOUT: %X.ref.loc27_62: type = name_ref X, file.%X.decl [concrete = constants.%X]
|
||||
// CHECK:STDOUT: %MaybeUnformed.loc27_63: type = class_type @MaybeUnformed, @MaybeUnformed(constants.%X) [concrete = constants.%MaybeUnformed.275]
|
||||
// CHECK:STDOUT: %.loc27_40: %MaybeUnformed.275 = converted %value.ref, <error> [concrete = <error>]
|
||||
// CHECK:STDOUT: %.loc27_30: type = splice_block %MaybeUnformed.loc27_30 [concrete = constants.%MaybeUnformed.275] {
|
||||
// CHECK:STDOUT: %Core.ref.loc27_10: <namespace> = name_ref Core, imports.%Core [concrete = imports.%Core]
|
||||
// CHECK:STDOUT: %MaybeUnformed.ref.loc27_14: %MaybeUnformed.type = name_ref MaybeUnformed, imports.%Core.MaybeUnformed [concrete = constants.%MaybeUnformed.generic]
|
||||
// CHECK:STDOUT: %X.ref.loc27_29: type = name_ref X, file.%X.decl [concrete = constants.%X]
|
||||
// CHECK:STDOUT: %MaybeUnformed.loc27_30: type = class_type @MaybeUnformed, @MaybeUnformed(constants.%X) [concrete = constants.%MaybeUnformed.275]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %v: %MaybeUnformed.275 = bind_name v, <error> [concrete = <error>]
|
||||
// CHECK:STDOUT: %X.as.Destroy.impl.Op.bound: <bound method> = bound_method %.loc19_39, constants.%X.as.Destroy.impl.Op
|
||||
// CHECK:STDOUT: %addr.loc19_39: %ptr.d17 = addr_of %.loc19_39
|
||||
// CHECK:STDOUT: %X.as.Destroy.impl.Op.call: init %empty_tuple.type = call %X.as.Destroy.impl.Op.bound(%addr.loc19_39)
|
||||
// CHECK:STDOUT: %MaybeUnformed.as.Destroy.impl.Op.bound: <bound method> = bound_method %i.var, constants.%MaybeUnformed.as.Destroy.impl.Op.b85
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %i.var, %MaybeUnformed.as.Destroy.impl.Op.specific_fn
|
||||
// CHECK:STDOUT: %addr.loc19_3: %ptr.58e = addr_of %i.var
|
||||
// CHECK:STDOUT: %MaybeUnformed.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method(%addr.loc19_3)
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @__global_init() {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- unsafe_remove_unformed.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %X: type = class_type @X [concrete]
|
||||
// CHECK:STDOUT: %ptr.d17: type = ptr_type %X [concrete]
|
||||
// CHECK:STDOUT: %pattern_type.1c6: type = pattern_type %ptr.d17 [concrete]
|
||||
// CHECK:STDOUT: %MaybeUnformed.275: type = class_type @MaybeUnformed, @MaybeUnformed(%X) [concrete]
|
||||
// CHECK:STDOUT: %ptr.58e: type = ptr_type %MaybeUnformed.275 [concrete]
|
||||
// CHECK:STDOUT: %reference.var: ref %X = var file.%reference.var_patt [concrete]
|
||||
// CHECK:STDOUT: %addr.a46: %ptr.d17 = addr_of %reference.var [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: imports {
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @Use() {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: name_binding_decl {
|
||||
// CHECK:STDOUT: %a.patt: %pattern_type.1c6 = binding_pattern a [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %reference.ref: ref %MaybeUnformed.275 = name_ref reference, file.%reference [concrete = file.%reference.var]
|
||||
// CHECK:STDOUT: %X.ref.loc11_37: type = name_ref X, file.%X.decl [concrete = constants.%X]
|
||||
// CHECK:STDOUT: %.loc11_34.1: ref %X = as_compatible %reference.ref [concrete = constants.%reference.var]
|
||||
// CHECK:STDOUT: %.loc11_34.2: ref %X = converted %reference.ref, %.loc11_34.1 [concrete = constants.%reference.var]
|
||||
// CHECK:STDOUT: %addr: %ptr.d17 = addr_of %.loc11_34.2 [concrete = constants.%addr.a46]
|
||||
// CHECK:STDOUT: %.loc11_11: type = splice_block %ptr.loc11 [concrete = constants.%ptr.d17] {
|
||||
// CHECK:STDOUT: %X.ref.loc11_10: type = name_ref X, file.%X.decl [concrete = constants.%X]
|
||||
// CHECK:STDOUT: %ptr.loc11: type = ptr_type %X.ref.loc11_10 [concrete = constants.%ptr.d17]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %a: %ptr.d17 = bind_name a, %addr
|
||||
// CHECK:STDOUT: name_binding_decl {
|
||||
// CHECK:STDOUT: %b.patt: %pattern_type.1c6 = binding_pattern b [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %ptr.ref: %ptr.58e = name_ref ptr, file.%ptr.loc7_5
|
||||
// CHECK:STDOUT: %X.ref.loc12_29: type = name_ref X, file.%X.decl [concrete = constants.%X]
|
||||
// CHECK:STDOUT: %ptr.loc12_30: type = ptr_type %X.ref.loc12_29 [concrete = constants.%ptr.d17]
|
||||
// CHECK:STDOUT: %.loc12_26.1: %ptr.d17 = as_compatible %ptr.ref
|
||||
// CHECK:STDOUT: %.loc12_26.2: %ptr.d17 = converted %ptr.ref, %.loc12_26.1
|
||||
// CHECK:STDOUT: %.loc12_11: type = splice_block %ptr.loc12_11 [concrete = constants.%ptr.d17] {
|
||||
// CHECK:STDOUT: %X.ref.loc12_10: type = name_ref X, file.%X.decl [concrete = constants.%X]
|
||||
// CHECK:STDOUT: %ptr.loc12_11: type = ptr_type %X.ref.loc12_10 [concrete = constants.%ptr.d17]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %b: %ptr.d17 = bind_name b, %.loc12_26.2
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @__global_init() {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
+380
@@ -0,0 +1,380 @@
|
||||
// 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
|
||||
//
|
||||
// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/convert.carbon
|
||||
//
|
||||
// AUTOUPDATE
|
||||
// TIP: To test this file alone, run:
|
||||
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/as/partial.carbon
|
||||
// TIP: To dump output, run:
|
||||
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/as/partial.carbon
|
||||
|
||||
// --- add_partial.carbon
|
||||
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
base class X {}
|
||||
|
||||
fn Init() -> X;
|
||||
let value: X = Init();
|
||||
var reference: X;
|
||||
let ptr: X* = &reference;
|
||||
|
||||
fn Use() {
|
||||
// TODO: Should some of these be valid without the `as`?
|
||||
//@dump-sem-ir-begin
|
||||
var i: partial X = Init() as partial X;
|
||||
let v: partial X = value as partial X;
|
||||
let a: partial X* = &(reference as partial X);
|
||||
let b: partial X* = ptr as partial X*;
|
||||
//@dump-sem-ir-end
|
||||
}
|
||||
|
||||
// --- fail_todo_remove_partial_in_init.carbon
|
||||
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
base class X {}
|
||||
|
||||
fn Init() -> partial X;
|
||||
|
||||
fn Use() {
|
||||
//@dump-sem-ir-begin
|
||||
// TODO: This should be valid, and should initialize the vptr. The explicit `as` should probably not be necessary.
|
||||
// CHECK:STDERR: fail_todo_remove_partial_in_init.carbon:[[@LINE+7]]:3: error: cannot implicitly convert expression of type `partial X` to `X` [ConversionFailure]
|
||||
// CHECK:STDERR: var i: X = Init();
|
||||
// CHECK:STDERR: ^~~~~~~~
|
||||
// CHECK:STDERR: fail_todo_remove_partial_in_init.carbon:[[@LINE+4]]:3: note: type `partial X` does not implement interface `Core.ImplicitAs(X)` [MissingImplInMemberAccessNote]
|
||||
// CHECK:STDERR: var i: X = Init();
|
||||
// CHECK:STDERR: ^~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
var i: X = Init();
|
||||
// CHECK:STDERR: fail_todo_remove_partial_in_init.carbon:[[@LINE+7]]:14: error: cannot convert expression of type `partial X` to `X` with `as` [ConversionFailure]
|
||||
// CHECK:STDERR: var j: X = Init() as X;
|
||||
// CHECK:STDERR: ^~~~~~~~~~~
|
||||
// CHECK:STDERR: fail_todo_remove_partial_in_init.carbon:[[@LINE+4]]:14: note: type `partial X` does not implement interface `Core.As(X)` [MissingImplInMemberAccessNote]
|
||||
// CHECK:STDERR: var j: X = Init() as X;
|
||||
// CHECK:STDERR: ^~~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
var j: X = Init() as X;
|
||||
// CHECK:STDERR: fail_todo_remove_partial_in_init.carbon:[[@LINE+7]]:14: error: cannot convert expression of type `partial X` to `X` with `unsafe as` [ConversionFailure]
|
||||
// CHECK:STDERR: var k: X = Init() unsafe as X;
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~
|
||||
// CHECK:STDERR: fail_todo_remove_partial_in_init.carbon:[[@LINE+4]]:14: note: type `partial X` does not implement interface `Core.UnsafeAs(X)` [MissingImplInMemberAccessNote]
|
||||
// CHECK:STDERR: var k: X = Init() unsafe as X;
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
var k: X = Init() unsafe as X;
|
||||
//@dump-sem-ir-end
|
||||
}
|
||||
|
||||
// --- fail_cannot_remove_partial.carbon
|
||||
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
base class X {}
|
||||
|
||||
fn Init() -> partial X;
|
||||
|
||||
let value: partial X = Init();
|
||||
var reference: partial X;
|
||||
let ptr: partial X* = &reference;
|
||||
|
||||
fn Use() {
|
||||
// CHECK:STDERR: fail_cannot_remove_partial.carbon:[[@LINE+7]]:14: error: cannot convert expression of type `partial X` to `X` with `as` [ConversionFailure]
|
||||
// CHECK:STDERR: let v: X = value as X;
|
||||
// CHECK:STDERR: ^~~~~~~~~~
|
||||
// CHECK:STDERR: fail_cannot_remove_partial.carbon:[[@LINE+4]]:14: note: type `partial X` does not implement interface `Core.As(X)` [MissingImplInMemberAccessNote]
|
||||
// CHECK:STDERR: let v: X = value as X;
|
||||
// CHECK:STDERR: ^~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
let v: X = value as X;
|
||||
// CHECK:STDERR: fail_cannot_remove_partial.carbon:[[@LINE+7]]:17: error: cannot convert expression of type `partial X` to `X` with `as` [ConversionFailure]
|
||||
// CHECK:STDERR: let a: X* = &(reference as X);
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~
|
||||
// CHECK:STDERR: fail_cannot_remove_partial.carbon:[[@LINE+4]]:17: note: type `partial X` does not implement interface `Core.As(X)` [MissingImplInMemberAccessNote]
|
||||
// CHECK:STDERR: let a: X* = &(reference as X);
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
let a: X* = &(reference as X);
|
||||
// CHECK:STDERR: fail_cannot_remove_partial.carbon:[[@LINE+7]]:15: error: cannot convert expression of type `partial X*` to `X*` with `as` [ConversionFailure]
|
||||
// CHECK:STDERR: let b: X* = ptr as X*;
|
||||
// CHECK:STDERR: ^~~~~~~~~
|
||||
// CHECK:STDERR: fail_cannot_remove_partial.carbon:[[@LINE+4]]:15: note: type `partial X*` does not implement interface `Core.As(X*)` [MissingImplInMemberAccessNote]
|
||||
// CHECK:STDERR: let b: X* = ptr as X*;
|
||||
// CHECK:STDERR: ^~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
let b: X* = ptr as X*;
|
||||
}
|
||||
|
||||
// --- unsafe_remove_partial.carbon
|
||||
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
base class X {}
|
||||
|
||||
fn Init() -> partial X;
|
||||
|
||||
let value: partial X = Init();
|
||||
var reference: partial X;
|
||||
let ptr: partial X* = &reference;
|
||||
|
||||
fn Use() {
|
||||
//@dump-sem-ir-begin
|
||||
let v: X = value unsafe as X;
|
||||
let a: X* = &(reference unsafe as X);
|
||||
let b: X* = ptr unsafe as X*;
|
||||
//@dump-sem-ir-end
|
||||
}
|
||||
|
||||
// CHECK:STDOUT: --- add_partial.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %X: type = class_type @X [concrete]
|
||||
// CHECK:STDOUT: %ptr.d17: type = ptr_type %X [concrete]
|
||||
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
|
||||
// CHECK:STDOUT: %Init.type: type = fn_type @Init [concrete]
|
||||
// CHECK:STDOUT: %Init: %Init.type = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %.e71: type = partial_type %X [concrete]
|
||||
// CHECK:STDOUT: %pattern_type.a53: type = pattern_type %.e71 [concrete]
|
||||
// CHECK:STDOUT: %ptr.7b2: type = ptr_type %.e71 [concrete]
|
||||
// CHECK:STDOUT: %pattern_type.46e: type = pattern_type %ptr.7b2 [concrete]
|
||||
// CHECK:STDOUT: %reference.var: ref %.e71 = var file.%reference.var_patt [concrete]
|
||||
// CHECK:STDOUT: %addr.e01: %ptr.7b2 = addr_of %reference.var [concrete]
|
||||
// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.057: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%.e71) [concrete]
|
||||
// CHECK:STDOUT: %T.as.Destroy.impl.Op.d31: %T.as.Destroy.impl.Op.type.057 = struct_value () [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: imports {
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @Use() {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: name_binding_decl {
|
||||
// CHECK:STDOUT: %i.patt: %pattern_type.a53 = binding_pattern i [concrete]
|
||||
// CHECK:STDOUT: %i.var_patt: %pattern_type.a53 = var_pattern %i.patt [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %i.var: ref %.e71 = var %i.var_patt
|
||||
// CHECK:STDOUT: %Init.ref: %Init.type = name_ref Init, file.%Init.decl [concrete = constants.%Init]
|
||||
// CHECK:STDOUT: %.loc14_3: ref %.e71 = splice_block %i.var {}
|
||||
// CHECK:STDOUT: %Init.call: init %X = call %Init.ref() to %.loc14_3
|
||||
// CHECK:STDOUT: %X.ref.loc14_40: type = name_ref X, file.%X.decl [concrete = constants.%X]
|
||||
// CHECK:STDOUT: %.loc14_32: type = partial_type %X.ref.loc14_40 [concrete = constants.%.e71]
|
||||
// CHECK:STDOUT: %.loc14_29.1: init %.e71 = as_compatible %Init.call
|
||||
// CHECK:STDOUT: %.loc14_29.2: init %.e71 = converted %Init.call, %.loc14_29.1
|
||||
// CHECK:STDOUT: assign %i.var, %.loc14_29.2
|
||||
// CHECK:STDOUT: %.loc14_10.1: type = splice_block %.loc14_10.2 [concrete = constants.%.e71] {
|
||||
// CHECK:STDOUT: %X.ref.loc14_18: type = name_ref X, file.%X.decl [concrete = constants.%X]
|
||||
// CHECK:STDOUT: %.loc14_10.2: type = partial_type %X.ref.loc14_18 [concrete = constants.%.e71]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %i: ref %.e71 = bind_name i, %i.var
|
||||
// CHECK:STDOUT: name_binding_decl {
|
||||
// CHECK:STDOUT: %v.patt: %pattern_type.a53 = binding_pattern v [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %value.ref: %X = name_ref value, file.%value
|
||||
// CHECK:STDOUT: %X.ref.loc15_39: type = name_ref X, file.%X.decl [concrete = constants.%X]
|
||||
// CHECK:STDOUT: %.loc15_31: type = partial_type %X.ref.loc15_39 [concrete = constants.%.e71]
|
||||
// CHECK:STDOUT: %.loc15_28.1: %.e71 = as_compatible %value.ref
|
||||
// CHECK:STDOUT: %.loc15_28.2: %.e71 = converted %value.ref, %.loc15_28.1
|
||||
// CHECK:STDOUT: %.loc15_10.1: type = splice_block %.loc15_10.2 [concrete = constants.%.e71] {
|
||||
// CHECK:STDOUT: %X.ref.loc15_18: type = name_ref X, file.%X.decl [concrete = constants.%X]
|
||||
// CHECK:STDOUT: %.loc15_10.2: type = partial_type %X.ref.loc15_18 [concrete = constants.%.e71]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %v: %.e71 = bind_name v, %.loc15_28.2
|
||||
// CHECK:STDOUT: name_binding_decl {
|
||||
// CHECK:STDOUT: %a.patt: %pattern_type.46e = binding_pattern a [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %reference.ref: ref %X = name_ref reference, file.%reference [concrete = file.%reference.var]
|
||||
// CHECK:STDOUT: %X.ref.loc16_46: type = name_ref X, file.%X.decl [concrete = constants.%X]
|
||||
// CHECK:STDOUT: %.loc16_38: type = partial_type %X.ref.loc16_46 [concrete = constants.%.e71]
|
||||
// CHECK:STDOUT: %.loc16_35.1: ref %.e71 = as_compatible %reference.ref [concrete = constants.%reference.var]
|
||||
// CHECK:STDOUT: %.loc16_35.2: ref %.e71 = converted %reference.ref, %.loc16_35.1 [concrete = constants.%reference.var]
|
||||
// CHECK:STDOUT: %addr.loc16: %ptr.7b2 = addr_of %.loc16_35.2 [concrete = constants.%addr.e01]
|
||||
// CHECK:STDOUT: %.loc16_19: type = splice_block %ptr.loc16 [concrete = constants.%ptr.7b2] {
|
||||
// CHECK:STDOUT: %X.ref.loc16_18: type = name_ref X, file.%X.decl [concrete = constants.%X]
|
||||
// CHECK:STDOUT: %.loc16_10: type = partial_type %X.ref.loc16_18 [concrete = constants.%.e71]
|
||||
// CHECK:STDOUT: %ptr.loc16: type = ptr_type %.loc16_10 [concrete = constants.%ptr.7b2]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %a: %ptr.7b2 = bind_name a, %addr.loc16
|
||||
// CHECK:STDOUT: name_binding_decl {
|
||||
// CHECK:STDOUT: %b.patt: %pattern_type.46e = binding_pattern b [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %ptr.ref: %ptr.d17 = name_ref ptr, file.%ptr.loc9_5
|
||||
// CHECK:STDOUT: %X.ref.loc17_38: type = name_ref X, file.%X.decl [concrete = constants.%X]
|
||||
// CHECK:STDOUT: %.loc17_30: type = partial_type %X.ref.loc17_38 [concrete = constants.%.e71]
|
||||
// CHECK:STDOUT: %ptr.loc17_39: type = ptr_type %.loc17_30 [concrete = constants.%ptr.7b2]
|
||||
// CHECK:STDOUT: %.loc17_27.1: %ptr.7b2 = as_compatible %ptr.ref
|
||||
// CHECK:STDOUT: %.loc17_27.2: %ptr.7b2 = converted %ptr.ref, %.loc17_27.1
|
||||
// CHECK:STDOUT: %.loc17_19: type = splice_block %ptr.loc17_19 [concrete = constants.%ptr.7b2] {
|
||||
// CHECK:STDOUT: %X.ref.loc17_18: type = name_ref X, file.%X.decl [concrete = constants.%X]
|
||||
// CHECK:STDOUT: %.loc17_10: type = partial_type %X.ref.loc17_18 [concrete = constants.%.e71]
|
||||
// CHECK:STDOUT: %ptr.loc17_19: type = ptr_type %.loc17_10 [concrete = constants.%ptr.7b2]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %b: %ptr.7b2 = bind_name b, %.loc17_27.2
|
||||
// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc14_3.1: <bound method> = bound_method %.loc14_3, constants.%T.as.Destroy.impl.Op.d31
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: %bound_method.loc14_3.1: <bound method> = bound_method %.loc14_3, %T.as.Destroy.impl.Op.specific_fn.1
|
||||
// CHECK:STDOUT: %addr.loc14_3.1: %ptr.7b2 = addr_of %.loc14_3
|
||||
// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc14_3.1: init %empty_tuple.type = call %bound_method.loc14_3.1(%addr.loc14_3.1)
|
||||
// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc14_3.2: <bound method> = bound_method %i.var, constants.%T.as.Destroy.impl.Op.d31
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: %bound_method.loc14_3.2: <bound method> = bound_method %i.var, %T.as.Destroy.impl.Op.specific_fn.2
|
||||
// CHECK:STDOUT: %addr.loc14_3.2: %ptr.7b2 = addr_of %i.var
|
||||
// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc14_3.2: init %empty_tuple.type = call %bound_method.loc14_3.2(%addr.loc14_3.2)
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @__global_init() {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- fail_todo_remove_partial_in_init.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %X: type = class_type @X [concrete]
|
||||
// CHECK:STDOUT: %ptr.d17: type = ptr_type %X [concrete]
|
||||
// CHECK:STDOUT: %X.as.Destroy.impl.Op.type: type = fn_type @X.as.Destroy.impl.Op [concrete]
|
||||
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
|
||||
// CHECK:STDOUT: %X.as.Destroy.impl.Op: %X.as.Destroy.impl.Op.type = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %.e71: type = partial_type %X [concrete]
|
||||
// CHECK:STDOUT: %Init.type: type = fn_type @Init [concrete]
|
||||
// CHECK:STDOUT: %Init: %Init.type = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %pattern_type.019: type = pattern_type %X [concrete]
|
||||
// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.057: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%.e71) [concrete]
|
||||
// CHECK:STDOUT: %T.as.Destroy.impl.Op.d31: %T.as.Destroy.impl.Op.type.057 = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %ptr.7b2: type = ptr_type %.e71 [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: imports {
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @Use() {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: name_binding_decl {
|
||||
// CHECK:STDOUT: %i.patt: %pattern_type.019 = binding_pattern i [concrete]
|
||||
// CHECK:STDOUT: %i.var_patt: %pattern_type.019 = var_pattern %i.patt [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %i.var: ref %X = var %i.var_patt
|
||||
// CHECK:STDOUT: %Init.ref.loc18: %Init.type = name_ref Init, file.%Init.decl [concrete = constants.%Init]
|
||||
// CHECK:STDOUT: %.loc18_19: ref %.e71 = temporary_storage
|
||||
// CHECK:STDOUT: %Init.call.loc18: init %.e71 = call %Init.ref.loc18() to %.loc18_19
|
||||
// CHECK:STDOUT: %.loc18_3: %X = converted %Init.call.loc18, <error> [concrete = <error>]
|
||||
// CHECK:STDOUT: assign %i.var, <error>
|
||||
// CHECK:STDOUT: %X.ref.loc18: type = name_ref X, file.%X.decl [concrete = constants.%X]
|
||||
// CHECK:STDOUT: %i: ref %X = bind_name i, %i.var
|
||||
// CHECK:STDOUT: name_binding_decl {
|
||||
// CHECK:STDOUT: %j.patt: %pattern_type.019 = binding_pattern j [concrete]
|
||||
// CHECK:STDOUT: %j.var_patt: %pattern_type.019 = var_pattern %j.patt [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %j.var: ref %X = var %j.var_patt
|
||||
// CHECK:STDOUT: %Init.ref.loc26: %Init.type = name_ref Init, file.%Init.decl [concrete = constants.%Init]
|
||||
// CHECK:STDOUT: %.loc26_19: ref %.e71 = temporary_storage
|
||||
// CHECK:STDOUT: %Init.call.loc26: init %.e71 = call %Init.ref.loc26() to %.loc26_19
|
||||
// CHECK:STDOUT: %X.ref.loc26_24: type = name_ref X, file.%X.decl [concrete = constants.%X]
|
||||
// CHECK:STDOUT: %.loc26_21: %X = converted %Init.call.loc26, <error> [concrete = <error>]
|
||||
// CHECK:STDOUT: assign %j.var, <error>
|
||||
// CHECK:STDOUT: %X.ref.loc26_10: type = name_ref X, file.%X.decl [concrete = constants.%X]
|
||||
// CHECK:STDOUT: %j: ref %X = bind_name j, %j.var
|
||||
// CHECK:STDOUT: name_binding_decl {
|
||||
// CHECK:STDOUT: %k.patt: %pattern_type.019 = binding_pattern k [concrete]
|
||||
// CHECK:STDOUT: %k.var_patt: %pattern_type.019 = var_pattern %k.patt [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %k.var: ref %X = var %k.var_patt
|
||||
// CHECK:STDOUT: %Init.ref.loc34: %Init.type = name_ref Init, file.%Init.decl [concrete = constants.%Init]
|
||||
// CHECK:STDOUT: %.loc34_19: ref %.e71 = temporary_storage
|
||||
// CHECK:STDOUT: %Init.call.loc34: init %.e71 = call %Init.ref.loc34() to %.loc34_19
|
||||
// CHECK:STDOUT: %X.ref.loc34_31: type = name_ref X, file.%X.decl [concrete = constants.%X]
|
||||
// CHECK:STDOUT: %.loc34_28: %X = converted %Init.call.loc34, <error> [concrete = <error>]
|
||||
// CHECK:STDOUT: assign %k.var, <error>
|
||||
// CHECK:STDOUT: %X.ref.loc34_10: type = name_ref X, file.%X.decl [concrete = constants.%X]
|
||||
// CHECK:STDOUT: %k: ref %X = bind_name k, %k.var
|
||||
// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc34: <bound method> = bound_method %.loc34_19, constants.%T.as.Destroy.impl.Op.d31
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: %bound_method.loc34: <bound method> = bound_method %.loc34_19, %T.as.Destroy.impl.Op.specific_fn.1
|
||||
// CHECK:STDOUT: %addr.loc34_19: %ptr.7b2 = addr_of %.loc34_19
|
||||
// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc34: init %empty_tuple.type = call %bound_method.loc34(%addr.loc34_19)
|
||||
// CHECK:STDOUT: %X.as.Destroy.impl.Op.bound.loc34: <bound method> = bound_method %k.var, constants.%X.as.Destroy.impl.Op
|
||||
// CHECK:STDOUT: %addr.loc34_3: %ptr.d17 = addr_of %k.var
|
||||
// CHECK:STDOUT: %X.as.Destroy.impl.Op.call.loc34: init %empty_tuple.type = call %X.as.Destroy.impl.Op.bound.loc34(%addr.loc34_3)
|
||||
// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc26: <bound method> = bound_method %.loc26_19, constants.%T.as.Destroy.impl.Op.d31
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: %bound_method.loc26: <bound method> = bound_method %.loc26_19, %T.as.Destroy.impl.Op.specific_fn.2
|
||||
// CHECK:STDOUT: %addr.loc26_19: %ptr.7b2 = addr_of %.loc26_19
|
||||
// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc26: init %empty_tuple.type = call %bound_method.loc26(%addr.loc26_19)
|
||||
// CHECK:STDOUT: %X.as.Destroy.impl.Op.bound.loc26: <bound method> = bound_method %j.var, constants.%X.as.Destroy.impl.Op
|
||||
// CHECK:STDOUT: %addr.loc26_3: %ptr.d17 = addr_of %j.var
|
||||
// CHECK:STDOUT: %X.as.Destroy.impl.Op.call.loc26: init %empty_tuple.type = call %X.as.Destroy.impl.Op.bound.loc26(%addr.loc26_3)
|
||||
// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc18: <bound method> = bound_method %.loc18_19, constants.%T.as.Destroy.impl.Op.d31
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: %bound_method.loc18: <bound method> = bound_method %.loc18_19, %T.as.Destroy.impl.Op.specific_fn.3
|
||||
// CHECK:STDOUT: %addr.loc18_19: %ptr.7b2 = addr_of %.loc18_19
|
||||
// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc18: init %empty_tuple.type = call %bound_method.loc18(%addr.loc18_19)
|
||||
// CHECK:STDOUT: %X.as.Destroy.impl.Op.bound.loc18: <bound method> = bound_method %i.var, constants.%X.as.Destroy.impl.Op
|
||||
// CHECK:STDOUT: %addr.loc18_3: %ptr.d17 = addr_of %i.var
|
||||
// CHECK:STDOUT: %X.as.Destroy.impl.Op.call.loc18: init %empty_tuple.type = call %X.as.Destroy.impl.Op.bound.loc18(%addr.loc18_3)
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- unsafe_remove_partial.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %X: type = class_type @X [concrete]
|
||||
// CHECK:STDOUT: %ptr.d17: type = ptr_type %X [concrete]
|
||||
// CHECK:STDOUT: %pattern_type.1c6: type = pattern_type %ptr.d17 [concrete]
|
||||
// CHECK:STDOUT: %.e71: type = partial_type %X [concrete]
|
||||
// CHECK:STDOUT: %ptr.7b2: type = ptr_type %.e71 [concrete]
|
||||
// CHECK:STDOUT: %pattern_type.019: type = pattern_type %X [concrete]
|
||||
// CHECK:STDOUT: %reference.var: ref %X = var file.%reference.var_patt [concrete]
|
||||
// CHECK:STDOUT: %addr.c6b: %ptr.d17 = addr_of %reference.var [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: imports {
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @Use() {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: name_binding_decl {
|
||||
// CHECK:STDOUT: %v.patt: %pattern_type.019 = binding_pattern v [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %value.ref: %.e71 = name_ref value, file.%value
|
||||
// CHECK:STDOUT: %X.ref.loc14_30: type = name_ref X, file.%X.decl [concrete = constants.%X]
|
||||
// CHECK:STDOUT: %.loc14_27.1: %X = as_compatible %value.ref
|
||||
// CHECK:STDOUT: %.loc14_27.2: %X = converted %value.ref, %.loc14_27.1
|
||||
// CHECK:STDOUT: %X.ref.loc14_10: type = name_ref X, file.%X.decl [concrete = constants.%X]
|
||||
// CHECK:STDOUT: %v: %X = bind_name v, %.loc14_27.2
|
||||
// CHECK:STDOUT: name_binding_decl {
|
||||
// CHECK:STDOUT: %a.patt: %pattern_type.1c6 = binding_pattern a [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %reference.ref: ref %.e71 = name_ref reference, file.%reference [concrete = file.%reference.var]
|
||||
// CHECK:STDOUT: %X.ref.loc15_37: type = name_ref X, file.%X.decl [concrete = constants.%X]
|
||||
// CHECK:STDOUT: %.loc15_34.1: ref %X = as_compatible %reference.ref [concrete = constants.%reference.var]
|
||||
// CHECK:STDOUT: %.loc15_34.2: ref %X = converted %reference.ref, %.loc15_34.1 [concrete = constants.%reference.var]
|
||||
// CHECK:STDOUT: %addr: %ptr.d17 = addr_of %.loc15_34.2 [concrete = constants.%addr.c6b]
|
||||
// CHECK:STDOUT: %.loc15_11: type = splice_block %ptr.loc15 [concrete = constants.%ptr.d17] {
|
||||
// CHECK:STDOUT: %X.ref.loc15_10: type = name_ref X, file.%X.decl [concrete = constants.%X]
|
||||
// CHECK:STDOUT: %ptr.loc15: type = ptr_type %X.ref.loc15_10 [concrete = constants.%ptr.d17]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %a: %ptr.d17 = bind_name a, %addr
|
||||
// CHECK:STDOUT: name_binding_decl {
|
||||
// CHECK:STDOUT: %b.patt: %pattern_type.1c6 = binding_pattern b [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %ptr.ref: %ptr.7b2 = name_ref ptr, file.%ptr.loc10_5
|
||||
// CHECK:STDOUT: %X.ref.loc16_29: type = name_ref X, file.%X.decl [concrete = constants.%X]
|
||||
// CHECK:STDOUT: %ptr.loc16_30: type = ptr_type %X.ref.loc16_29 [concrete = constants.%ptr.d17]
|
||||
// CHECK:STDOUT: %.loc16_26.1: %ptr.d17 = as_compatible %ptr.ref
|
||||
// CHECK:STDOUT: %.loc16_26.2: %ptr.d17 = converted %ptr.ref, %.loc16_26.1
|
||||
// CHECK:STDOUT: %.loc16_11: type = splice_block %ptr.loc16_11 [concrete = constants.%ptr.d17] {
|
||||
// CHECK:STDOUT: %X.ref.loc16_10: type = name_ref X, file.%X.decl [concrete = constants.%X]
|
||||
// CHECK:STDOUT: %ptr.loc16_11: type = ptr_type %X.ref.loc16_10 [concrete = constants.%ptr.d17]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %b: %ptr.d17 = bind_name b, %.loc16_26.2
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @__global_init() {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
+2
-54
@@ -2,7 +2,7 @@
|
||||
// Exceptions. See /LICENSE for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/convert.carbon
|
||||
// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/unformed.carbon
|
||||
//
|
||||
// AUTOUPDATE
|
||||
// TIP: To test this file alone, run:
|
||||
@@ -10,18 +10,6 @@
|
||||
// TIP: To dump output, run:
|
||||
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/as/unsafe_as.carbon
|
||||
|
||||
// --- qualifiers.carbon
|
||||
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
class X {}
|
||||
|
||||
fn Convert(p: const X*) -> X* {
|
||||
//@dump-sem-ir-begin
|
||||
return p unsafe as X*;
|
||||
//@dump-sem-ir-end
|
||||
}
|
||||
|
||||
// --- fail_no_conversion.carbon
|
||||
|
||||
library "[[@TEST_NAME]]";
|
||||
@@ -30,7 +18,7 @@ class A {};
|
||||
class B {};
|
||||
|
||||
fn Convert(a: A) -> B {
|
||||
// CHECK:STDERR: fail_no_conversion.carbon:[[@LINE+7]]:10: error: cannot convert expression of type `A` to `B` with `as` [ConversionFailure]
|
||||
// CHECK:STDERR: fail_no_conversion.carbon:[[@LINE+7]]:10: error: cannot convert expression of type `A` to `B` with `unsafe as` [ConversionFailure]
|
||||
// CHECK:STDERR: return a unsafe as B;
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~
|
||||
// CHECK:STDERR: fail_no_conversion.carbon:[[@LINE+4]]:10: note: type `A` does not implement interface `Core.UnsafeAs(B)` [MissingImplInMemberAccessNote]
|
||||
@@ -39,43 +27,3 @@ fn Convert(a: A) -> B {
|
||||
// CHECK:STDERR:
|
||||
return a unsafe as B;
|
||||
}
|
||||
|
||||
// --- fail_remove_qualifiers_without_unsafe.carbon
|
||||
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
class X {}
|
||||
|
||||
fn Convert(p: const X*) -> X* {
|
||||
// CHECK:STDERR: fail_remove_qualifiers_without_unsafe.carbon:[[@LINE+7]]:10: error: cannot convert expression of type `const X*` to `X*` with `as` [ConversionFailure]
|
||||
// CHECK:STDERR: return p as X*;
|
||||
// CHECK:STDERR: ^~~~~~~
|
||||
// CHECK:STDERR: fail_remove_qualifiers_without_unsafe.carbon:[[@LINE+4]]:10: note: type `const X*` does not implement interface `Core.As(X*)` [MissingImplInMemberAccessNote]
|
||||
// CHECK:STDERR: return p as X*;
|
||||
// CHECK:STDERR: ^~~~~~~
|
||||
// CHECK:STDERR:
|
||||
return p as X*;
|
||||
}
|
||||
|
||||
// CHECK:STDOUT: --- qualifiers.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %X: type = class_type @X [concrete]
|
||||
// CHECK:STDOUT: %ptr.d17: type = ptr_type %X [concrete]
|
||||
// CHECK:STDOUT: %const: type = const_type %X [concrete]
|
||||
// CHECK:STDOUT: %ptr.cbd: type = ptr_type %const [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: imports {
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @Convert(%p.param: %ptr.cbd) -> %ptr.d17 {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %p.ref: %ptr.cbd = name_ref p, %p
|
||||
// CHECK:STDOUT: %X.ref.loc8: type = name_ref X, file.%X.decl [concrete = constants.%X]
|
||||
// CHECK:STDOUT: %ptr.loc8: type = ptr_type %X.ref.loc8 [concrete = constants.%ptr.d17]
|
||||
// CHECK:STDOUT: %.loc8_19.1: %ptr.d17 = as_compatible %p.ref
|
||||
// CHECK:STDOUT: %.loc8_19.2: %ptr.d17 = converted %p.ref, %.loc8_19.1
|
||||
// CHECK:STDOUT: return %.loc8_19.2
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
|
||||
@@ -56,6 +56,13 @@ class DeriveFromi32 {
|
||||
|
||||
// It's not really important whether this conversion produces an error or not,
|
||||
// but it shouldn't crash.
|
||||
// CHECK:STDERR: fail_derive_from_i32.carbon:[[@LINE+7]]:53: error: cannot implicitly convert expression of type `DeriveFromi32*` to `i32*` [ConversionFailure]
|
||||
// CHECK:STDERR: fn ConvertToBadBasei32(p: DeriveFromi32*) -> i32* { return p; }
|
||||
// CHECK:STDERR: ^~~~~~~~~
|
||||
// CHECK:STDERR: fail_derive_from_i32.carbon:[[@LINE+4]]:53: note: type `DeriveFromi32*` does not implement interface `Core.ImplicitAs(i32*)` [MissingImplInMemberAccessNote]
|
||||
// CHECK:STDERR: fn ConvertToBadBasei32(p: DeriveFromi32*) -> i32* { return p; }
|
||||
// CHECK:STDERR: ^~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
fn ConvertToBadBasei32(p: DeriveFromi32*) -> i32* { return p; }
|
||||
|
||||
// CHECK:STDERR: fail_derive_from_i32.carbon:[[@LINE+4]]:70: error: member name `n` not found in `DeriveFromi32` [MemberNameNotFoundInInstScope]
|
||||
|
||||
@@ -178,6 +178,13 @@ library "[[@TEST_NAME]]";
|
||||
import Cpp library "virtual_inheritance.h";
|
||||
|
||||
fn Convert(p: Cpp.B*) -> Cpp.A* {
|
||||
// CHECK:STDERR: fail_todo_use_virtual_inheritance.carbon:[[@LINE+21]]:3: error: semantics TODO: `class with virtual bases` [SemanticsTodo]
|
||||
// CHECK:STDERR: return p;
|
||||
// CHECK:STDERR: ^~~~~~~~~
|
||||
// CHECK:STDERR: fail_todo_use_virtual_inheritance.carbon:[[@LINE+18]]:3: note: while completing C++ type `Cpp.B` [InCppTypeCompletion]
|
||||
// CHECK:STDERR: return p;
|
||||
// CHECK:STDERR: ^~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
// CHECK:STDERR: fail_todo_use_virtual_inheritance.carbon:[[@LINE+14]]:3: error: semantics TODO: `class with virtual bases` [SemanticsTodo]
|
||||
// CHECK:STDERR: return p;
|
||||
// CHECK:STDERR: ^~~~~~~~~
|
||||
|
||||
@@ -138,10 +138,20 @@ auto GetConstType(Context& context, SemIR::TypeInstId inner_type_id)
|
||||
|
||||
auto GetQualifiedType(Context& context, SemIR::TypeId type_id,
|
||||
SemIR::TypeQualifiers quals) -> SemIR::TypeId {
|
||||
if ((quals & SemIR::TypeQualifiers::Const) != SemIR::TypeQualifiers::None) {
|
||||
if (HasTypeQualifier(quals, SemIR::TypeQualifiers::Const)) {
|
||||
type_id = GetConstType(context, context.types().GetInstId(type_id));
|
||||
quals &= ~SemIR::TypeQualifiers::Const;
|
||||
}
|
||||
if (HasTypeQualifier(quals, SemIR::TypeQualifiers::MaybeUnformed)) {
|
||||
type_id = GetTypeImpl<SemIR::MaybeUnformedType>(
|
||||
context, context.types().GetInstId(type_id));
|
||||
quals &= ~SemIR::TypeQualifiers::MaybeUnformed;
|
||||
}
|
||||
if (HasTypeQualifier(quals, SemIR::TypeQualifiers::Partial)) {
|
||||
type_id = GetTypeImpl<SemIR::PartialType>(
|
||||
context, context.types().GetInstId(type_id));
|
||||
quals &= ~SemIR::TypeQualifiers::Partial;
|
||||
}
|
||||
CARBON_CHECK(quals == SemIR::TypeQualifiers::None);
|
||||
return type_id;
|
||||
}
|
||||
|
||||
@@ -764,8 +764,7 @@ static auto BuildTypeForInst(FileContext& context, SemIR::ClassType inst)
|
||||
}
|
||||
|
||||
template <typename InstT>
|
||||
requires(InstT::Kind.template IsAnyOf<
|
||||
SemIR::ConstType, SemIR::MaybeUnformedType, SemIR::PartialType>())
|
||||
requires(SemIR::Internal::HasInstCategory<SemIR::AnyQualifiedType, InstT>)
|
||||
static auto BuildTypeForInst(FileContext& context, InstT inst) -> llvm::Type* {
|
||||
return context.GetType(
|
||||
context.sem_ir().types().GetTypeIdForTypeInstId(inst.inner_id));
|
||||
|
||||
@@ -167,6 +167,18 @@ struct AnyParamPattern {
|
||||
CallParamIndex index;
|
||||
};
|
||||
|
||||
// A type qualifier that wraps another type and has the same object
|
||||
// representation. Qualifiers are arranged so that adding a qualifier is
|
||||
// generally safe, and removing a qualifier is not necessarily safe or correct.
|
||||
struct AnyQualifiedType {
|
||||
using CategoryInfo = CategoryOf<ConstType, PartialType, MaybeUnformedType>;
|
||||
|
||||
InstKind kind;
|
||||
|
||||
TypeId type_id;
|
||||
TypeInstId inner_id;
|
||||
};
|
||||
|
||||
// A struct-like type with a list of named fields.
|
||||
struct AnyStructType {
|
||||
using CategoryInfo = CategoryOf<StructType, CustomLayoutType>;
|
||||
|
||||
@@ -95,12 +95,42 @@ auto TypeStore::GetTransitiveAdaptedType(TypeId type_id) const -> TypeId {
|
||||
|
||||
auto TypeStore::GetUnqualifiedTypeAndQualifiers(TypeId type_id) const
|
||||
-> std::pair<TypeId, TypeQualifiers> {
|
||||
if (auto const_type = TryGetAs<ConstType>(type_id)) {
|
||||
return {file_->types().GetTypeIdForTypeInstId(const_type->inner_id),
|
||||
TypeQualifiers::Const};
|
||||
TypeQualifiers quals = TypeQualifiers::None;
|
||||
while (true) {
|
||||
if (auto qualified_type = TryGetAs<AnyQualifiedType>(type_id)) {
|
||||
type_id = file_->types().GetTypeIdForTypeInstId(qualified_type->inner_id);
|
||||
switch (qualified_type->kind) {
|
||||
case ConstType::Kind:
|
||||
quals |= TypeQualifiers::Const;
|
||||
break;
|
||||
case MaybeUnformedType::Kind:
|
||||
quals |= TypeQualifiers::MaybeUnformed;
|
||||
break;
|
||||
case PartialType::Kind:
|
||||
quals |= TypeQualifiers::Partial;
|
||||
break;
|
||||
default:
|
||||
CARBON_FATAL("Unknown type qualifier {0}", qualified_type->kind);
|
||||
}
|
||||
} else {
|
||||
return {type_id, quals};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto TypeStore::GetTransitiveUnqualifiedAdaptedType(TypeId type_id) const
|
||||
-> std::pair<TypeId, TypeQualifiers> {
|
||||
TypeQualifiers quals = TypeQualifiers::None;
|
||||
while (true) {
|
||||
type_id = GetTransitiveAdaptedType(type_id);
|
||||
auto [unqual_type_id, inner_quals] =
|
||||
GetUnqualifiedTypeAndQualifiers(type_id);
|
||||
if (unqual_type_id == type_id) {
|
||||
return {type_id, quals};
|
||||
}
|
||||
type_id = unqual_type_id;
|
||||
quals |= inner_quals;
|
||||
}
|
||||
// TODO: Look through PartialType when this is reachable/testable
|
||||
return {type_id, TypeQualifiers::None};
|
||||
}
|
||||
|
||||
auto TypeStore::TryGetIntTypeInfo(TypeId int_type_id) const
|
||||
|
||||
+14
-2
@@ -21,11 +21,18 @@ LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
|
||||
enum class TypeQualifiers {
|
||||
None = 0,
|
||||
Const = 1 << 0,
|
||||
// TODO: Partial
|
||||
MaybeUnformed = 1 << 1,
|
||||
Partial = 1 << 2,
|
||||
|
||||
LLVM_MARK_AS_BITMASK_ENUM(Const)
|
||||
LLVM_MARK_AS_BITMASK_ENUM(Partial)
|
||||
};
|
||||
|
||||
// Returns whether the type qualifier set `quals` contains `qual`.
|
||||
inline auto HasTypeQualifier(TypeQualifiers quals, TypeQualifiers qual)
|
||||
-> bool {
|
||||
return (quals & qual) != TypeQualifiers::None;
|
||||
}
|
||||
|
||||
// Provides a ValueStore wrapper with an API specific to types.
|
||||
class TypeStore : public Yaml::Printable<TypeStore> {
|
||||
public:
|
||||
@@ -182,6 +189,11 @@ class TypeStore : public Yaml::Printable<TypeStore> {
|
||||
auto GetUnqualifiedTypeAndQualifiers(TypeId type_id) const
|
||||
-> std::pair<TypeId, TypeQualifiers>;
|
||||
|
||||
// Returns the non-adapter unqualified type that is compatible with the
|
||||
// specified type.
|
||||
auto GetTransitiveUnqualifiedAdaptedType(TypeId type_id) const
|
||||
-> std::pair<TypeId, TypeQualifiers>;
|
||||
|
||||
// Determines whether the given type is a signed integer type. This includes
|
||||
// the case where the type is `Core.IntLiteral` or a class type whose object
|
||||
// representation is a signed integer type.
|
||||
|
||||
@@ -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
|
||||
//
|
||||
// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/parts/destroy.carbon
|
||||
|
||||
// --- min_prelude/parts/maybe_unformed.carbon
|
||||
|
||||
package Core library "prelude/parts/maybe_unformed";
|
||||
|
||||
export import library "prelude/parts/destroy";
|
||||
|
||||
private fn Make(t: type) -> type = "maybe_unformed.make_type";
|
||||
|
||||
class MaybeUnformed(T:! type) {
|
||||
adapt Make(T);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
// 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
|
||||
//
|
||||
// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/parts/as.carbon
|
||||
// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/parts/maybe_unformed.carbon
|
||||
// EXTRA-ARGS: --custom-core --exclude-dump-file-prefix=min_prelude/
|
||||
|
||||
// --- min_prelude/uint.carbon
|
||||
|
||||
// A minimal prelude for test involving `Core.MaybeUnformed(T)`.
|
||||
package Core library "prelude";
|
||||
|
||||
export import library "prelude/parts/as";
|
||||
export import library "prelude/parts/maybe_unformed";
|
||||
Reference in New Issue
Block a user