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:
Richard Smith
2025-09-03 21:00:12 +00:00
committed by GitHub
parent 10fab24451
commit cb5e2e1597
15 changed files with 1285 additions and 100 deletions
+103 -33
View File
@@ -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);
}
});
+12 -3
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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: ^~~~~~~~~
+11 -1
View File
@@ -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;
}
+1 -2
View File
@@ -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));
+12
View File
@@ -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>;
+35 -5
View File
@@ -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
View File
@@ -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);
}
+15
View File
@@ -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";