mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 18:41:08 +01:00
The main direction of this change is the edits to `destroy.carbon` (matching in both prelude and min_prelude). Previously there was a no-op blanket impl for `Destroy`, which hid all missing implementations of `Destroy`. This does a few things: - Sets up builtin aggregate destruction for struct and tuple types as before, but also adds C++ class types and array types to the same handling. (all as a TODO for actual implementation) - Also maybe-unformed destruction, for now at least. (there's a chance I may try a different approach on this, but the impl lookup wasn't working as I'd hope in order to write it in code) - Adds handlers for simple things that are easy to do in code: `type`, `bool`, pointers. (because these are no-op destruction) - Redirect `const T` destruction to `T` destruction. This leaves as future issues: - `partial T` destruction. (this can't be done similar to `const` because it only works for non-`final` class types; I think `class` definitions should just generate what's needed) - Destruction of other prelude-provided types. (will probably come up as we implement class destruction, that the adapted builtin type doesn't implement `Destroy` -- but may end up special-casing that in a way that moots it) This moves the `&` operator from `facet_types.carbon` to `convert.carbon` because more things need to handle type and now that we're getting separate copy and destroy interfaces. It should be low-cost (an interface and builtin) so hopefully this is the right balance for complexity and re-use. A few tests are also edited in order to focus them more on what they intend to test, and avoid a `Destroy` dependency.
129 lines
3.4 KiB
Plaintext
129 lines
3.4 KiB
Plaintext
// 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/impl/lookup/find_in_final.carbon
|
|
// TIP: To dump output, run:
|
|
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/impl/lookup/find_in_final.carbon
|
|
|
|
// --- final_impl_precedence_over_facet.carbon
|
|
library "[[@TEST_NAME]]";
|
|
interface I {
|
|
let T:! type;
|
|
}
|
|
|
|
final impl forall [U:! type] U as I where .T = () {}
|
|
|
|
fn F(V:! I) -> V.T {
|
|
// Even though we have a witness that `V impls I` from the constraint on `I`,
|
|
// we should do an impl lookup to see if any effectively final impl applies
|
|
// when we find an unknown value in that witness. In this case, that lookup
|
|
// would find an impl with more specific values for associated constants that
|
|
// we should merge.
|
|
return ();
|
|
}
|
|
|
|
// --- final_impl_precedence_over_facet_with_where.carbon
|
|
library "[[@TEST_NAME]]";
|
|
|
|
interface Z {
|
|
let X:! type;
|
|
let Y:! type;
|
|
}
|
|
|
|
final impl forall [T:! type] T as Z where .X = () and .Y = () {}
|
|
|
|
fn F(ZZ:! Z where .X = ()) {
|
|
// Z.Y is unspecified on `ZZ` so it's found on the final impl where it's known
|
|
// to be the concrete type (), which can then be used in this generic
|
|
// function.
|
|
let a: ZZ.Y = ();
|
|
}
|
|
|
|
// --- final_impl_precedence_over_facet_access_type_with_where.carbon
|
|
library "[[@TEST_NAME]]";
|
|
|
|
interface Z {
|
|
let X:! type;
|
|
let Y:! type;
|
|
}
|
|
|
|
final impl forall [T:! type] T as Z where .X = () and .Y = () {}
|
|
|
|
fn F[T:! Z where .X = ()](z: T) {
|
|
// z.Y is unspecified on `ZZ` so it's found on the final impl where it's known
|
|
// to be the concrete type (), which can then be used in this generic
|
|
// function.
|
|
let a: z.Y = ();
|
|
}
|
|
|
|
// --- final_impl_makes_compatible_facet_values.carbon
|
|
library "[[@TEST_NAME]]";
|
|
|
|
interface I { let X:! type; }
|
|
interface J {}
|
|
|
|
final impl forall [T:! J] T as I where .X = () {}
|
|
|
|
class C(T:! I) {
|
|
var b: T.X;
|
|
}
|
|
|
|
class D(T:! J) {
|
|
var c: C(T)*;
|
|
}
|
|
|
|
fn F(T:! I & J) -> () {
|
|
// The witness for `I` found here directly, and inside `D` from a FacetValue
|
|
// come from the same facet, the `T` binding in the params of F, so they
|
|
// should be compatible.
|
|
var x: C(T);
|
|
var y: D(T);
|
|
y.c = &x;
|
|
return (*y.c).b;
|
|
}
|
|
|
|
// --- non_final_impl_makes_compatible_facet_values.carbon
|
|
library "[[@TEST_NAME]]";
|
|
|
|
interface I { let X:! type; }
|
|
interface J {}
|
|
|
|
impl forall [T:! J] T as I where .X = () {}
|
|
|
|
class C(T:! I) {
|
|
var b: T.X;
|
|
}
|
|
|
|
class D(T:! J) {
|
|
var c: C(T)*;
|
|
}
|
|
|
|
fn F(T:! I & J) -> T.(I.X)* {
|
|
var x: C(T);
|
|
var y: D(T);
|
|
// The witness for `I` found here directly, and inside `D` from a FacetValue
|
|
// come from the same facet, the `T` binding in the params of F, so they
|
|
// should be compatible.
|
|
y.c = &x;
|
|
return &(*y.c).b;
|
|
}
|
|
|
|
// --- todo_fail_facet_value_rewrite_incompatible_with_final_impl.carbon
|
|
library "[[@TEST_NAME]]";
|
|
|
|
interface Z {
|
|
let X:! type;
|
|
}
|
|
|
|
final impl forall [T:! type] T as Z where .X = () {}
|
|
|
|
// TODO: This should be diagnosed as there is a final impl defining `.X = ()`,
|
|
// which makes the LHS of this rewrite constraint concrete. And since the RHS is
|
|
// not the same (or convertible from), the rewrite is impossible.
|
|
fn F(ZZ:! Z where .X = {.r: ()}) {}
|