-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Add failing tests for exposing the value of .Self through an interface #5957
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
danakj
merged 15 commits into
carbon-language:trunk
from
danakj:test-call-returning-facet-value
Oct 8, 2025
+750
−0
Merged
Changes from all commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
707a695
test-call-returning-facet-value
danakj bf88efe
moretests
danakj 2c12c8c
add-file
danakj 3d97c04
fail_todo_
danakj fd9072a
compounds
danakj b63fa6e
adjust-nesting
danakj a3556b2
review
danakj d0f8f7c
review
danakj afc3467
typo
danakj 7bd92f8
Merge branch 'trunk' into test-call-returning-facet-value
danakj c2578ca
diagnostics-changed
danakj 5583449
review
danakj 6e3bc59
Merge remote-tracking branch 'origin/trunk' into test-call-returning-…
danakj ff7183b
apply-core-destroy
danakj b5b219a
test-type-and-self-parameter
danakj File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -80,6 +80,207 @@ fn UseIndirect[T:! I](x: T) -> T { | |
//@dump-sem-ir-end | ||
} | ||
|
||
// --- fail_todo_convert_from_period_self_to_full_facet_value.carbon | ||
library "[[@TEST_NAME]]"; | ||
|
||
interface I { | ||
let I1:! type; | ||
} | ||
|
||
fn F(U:! I where .I1 = .Self) { | ||
// CHECK:STDERR: fail_todo_convert_from_period_self_to_full_facet_value.carbon:[[@LINE+4]]:3: error: cannot convert type `U` that implements `I where .(I.I1) = .Self` into type implementing `I where .(I.I1) = U` [ConversionFailureFacetToFacet] | ||
// CHECK:STDERR: U as (I where .I1 = U); | ||
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~ | ||
// CHECK:STDERR: | ||
U as (I where .I1 = U); | ||
// CHECK:STDERR: fail_todo_convert_from_period_self_to_full_facet_value.carbon:[[@LINE+4]]:3: error: cannot convert type `U` that implements `I where .(I.I1) = .Self` into type implementing `I where .(I.I1) = U` [ConversionFailureFacetToFacet] | ||
// CHECK:STDERR: (U as type) as (I where .I1 = U); | ||
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
// CHECK:STDERR: | ||
(U as type) as (I where .I1 = U); | ||
} | ||
|
||
// --- convert_to_period_self.carbon | ||
library "[[@TEST_NAME]]"; | ||
|
||
interface I { | ||
let I1:! type; | ||
let I2:! type; | ||
} | ||
|
||
fn F(U:! I where .I1 = .Self and .I2 = ()) { | ||
U as (I where .I1 = .Self); | ||
(U as type) as (I where .I1 = .Self); | ||
} | ||
|
||
// --- fail_todo_access_through_call_once.carbon | ||
library "[[@TEST_NAME]]"; | ||
|
||
// TODO: Merge this test with the one below once they both work. | ||
|
||
interface I { | ||
let X:! type; | ||
fn G() -> X*; | ||
} | ||
|
||
fn F2[U:! I](V: U*) {} | ||
|
||
fn F(U:! I where .X = .Self, V: U) { | ||
// The returned value of `G` type `U` which has access to the methods of `I`. | ||
U.G()->G(); | ||
// CHECK:STDERR: fail_todo_access_through_call_once.carbon:[[@LINE+4]]:3: error: type `type` does not support qualified expressions [QualifiedExprUnsupported] | ||
// CHECK:STDERR: (U as type).G()->G(); | ||
// CHECK:STDERR: ^~~~~~~~~~~~~ | ||
// CHECK:STDERR: | ||
(U as type).G()->G(); | ||
|
||
// The returned value of type `U` can be used as a value of type `U`. | ||
F2(U.G()); | ||
} | ||
|
||
// --- fail_todo_access_through_call.carbon | ||
library "[[@TEST_NAME]]"; | ||
|
||
interface I { | ||
let X:! type; | ||
fn G() -> X*; | ||
} | ||
|
||
fn F2[U:! I](V: U*) {} | ||
fn F3[U:! I where .X = .Self](V: U*) {} | ||
|
||
fn F(U:! I where .X = .Self, V: U*) { | ||
// The returned value of `G` type `U` which has access to the methods of `I`. | ||
// | ||
// TODO: These should work. | ||
// - The first `.` is on a NameRef of type FacetType for `I where .X = .Self`. | ||
// - This finds `G` through the FacetType. | ||
// - The second `.` is on a Call of type FacetAccessType into `BindSymbolicName` with type FacetType for `I`. | ||
// - This finds `G` through the FacetType (impl lookup strips off FacetAccessType). | ||
// - The third `.` is on a Call of type FacetAccessType into `ImplWitnessAccess` of `I.X` into `LookupImplWitness`, which has type `type` | ||
// - Can't make calls on an `ImplWitnessAccess`. | ||
danakj marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// - We could expect that the constant value of the `ImplWitnessAccess` would | ||
// be the same type that we got for the second lookup. | ||
// CHECK:STDERR: fail_todo_access_through_call.carbon:[[@LINE+4]]:3: error: type `.(I.X)` does not support qualified expressions [QualifiedExprUnsupported] | ||
// CHECK:STDERR: U.G()->G()->G(); | ||
// CHECK:STDERR: ^~~~~~~~~~~~~ | ||
// CHECK:STDERR: | ||
U.G()->G()->G(); | ||
// CHECK:STDERR: fail_todo_access_through_call.carbon:[[@LINE+4]]:3: error: type `type` does not support qualified expressions [QualifiedExprUnsupported] | ||
// CHECK:STDERR: (U as type).G()->G()->G(); | ||
// CHECK:STDERR: ^~~~~~~~~~~~~ | ||
// CHECK:STDERR: | ||
(U as type).G()->G()->G(); | ||
|
||
// The returned value of type `U` can be used as a value of type `U`. | ||
// | ||
// TODO: This should work. | ||
// CHECK:STDERR: fail_todo_access_through_call.carbon:[[@LINE+4]]:6: error: type `.(I.X)` does not support qualified expressions [QualifiedExprUnsupported] | ||
// CHECK:STDERR: F2(U.G()->G()->G()); | ||
// CHECK:STDERR: ^~~~~~~~~~~~~ | ||
// CHECK:STDERR: | ||
F2(U.G()->G()->G()); | ||
|
||
// The constraints in the type `U` are preserved. | ||
// | ||
// TODO: These should work. | ||
// CHECK:STDERR: fail_todo_access_through_call.carbon:[[@LINE+7]]:3: error: cannot convert type `.Self` that implements `I` into type implementing `I where .(I.X) = .Self` [ConversionFailureFacetToFacet] | ||
// CHECK:STDERR: F3(U.G()); | ||
// CHECK:STDERR: ^~~~~~~~~ | ||
// CHECK:STDERR: fail_todo_access_through_call.carbon:[[@LINE-40]]:1: note: while deducing parameters of generic declared here [DeductionGenericHere] | ||
// CHECK:STDERR: fn F3[U:! I where .X = .Self](V: U*) {} | ||
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
// CHECK:STDERR: | ||
F3(U.G()); | ||
// CHECK:STDERR: fail_todo_access_through_call.carbon:[[@LINE+4]]:6: error: type `.(I.X)` does not support qualified expressions [QualifiedExprUnsupported] | ||
// CHECK:STDERR: F3(U.G()->G()->G()); | ||
// CHECK:STDERR: ^~~~~~~~~~~~~ | ||
// CHECK:STDERR: | ||
F3(U.G()->G()->G()); | ||
} | ||
|
||
// --- fail_todo_compound_access_through_call.carbon | ||
library "[[@TEST_NAME]]"; | ||
|
||
interface I { | ||
let X:! type; | ||
fn G() -> X; | ||
} | ||
|
||
fn F(U:! I where .X = .Self) { | ||
// Compound member lookup through a non-type value is possible for methods | ||
// which take a `self` parameter. But it's not possible for methods without | ||
// `self`. For those you need to go directly throug the type. | ||
// See: https://github.com/carbon-language/carbon-lang/issues/6025 | ||
|
||
// TODO: This step should work. | ||
// | ||
// CHECK:STDERR: fail_todo_compound_access_through_call.carbon:[[@LINE+7]]:14: error: cannot implicitly convert expression of type `.Self` to `U` [ConversionFailure] | ||
// CHECK:STDERR: let u: U = U.(I.G)(); | ||
// CHECK:STDERR: ^~~~~~~~~ | ||
// CHECK:STDERR: fail_todo_compound_access_through_call.carbon:[[@LINE+4]]:14: note: type `.Self` does not implement interface `Core.ImplicitAs(U)` [MissingImplInMemberAccessNote] | ||
// CHECK:STDERR: let u: U = U.(I.G)(); | ||
// CHECK:STDERR: ^~~~~~~~~ | ||
// CHECK:STDERR: | ||
let u: U = U.(I.G)(); | ||
// `u` is a non-type value. Can call methods with `self` through compound | ||
// member lookup, but can't call methods without `self`. See the | ||
// `compound_access_through_call_with_self_param.carbon` test for the former. | ||
// | ||
// CHECK:STDERR: fail_todo_compound_access_through_call.carbon:[[@LINE+7]]:3: error: cannot implicitly convert non-type value of type `U` into type implementing `I` [ConversionFailureNonTypeToFacet] | ||
// CHECK:STDERR: u.(I.G)(); | ||
// CHECK:STDERR: ^~~~~~~ | ||
// CHECK:STDERR: fail_todo_compound_access_through_call.carbon:[[@LINE+4]]:3: note: type `U` does not implement interface `Core.ImplicitAs(I)` [MissingImplInMemberAccessNote] | ||
// CHECK:STDERR: u.(I.G)(); | ||
// CHECK:STDERR: ^~~~~~~ | ||
// CHECK:STDERR: | ||
u.(I.G)(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would it make sense to split this and the next line out from the file that contains the previous let declaration, so that we don't have a mixture of "should not fail but does" and "should fail and does" in the same file? |
||
|
||
// This is the same as the above, since G() returns a non-type value of type | ||
// `U`. | ||
// | ||
// CHECK:STDERR: fail_todo_compound_access_through_call.carbon:[[@LINE+7]]:3: error: cannot implicitly convert non-type value of type `.Self` into type implementing `I` [ConversionFailureNonTypeToFacet] | ||
// CHECK:STDERR: U.(I.G)().(I.G)(); | ||
// CHECK:STDERR: ^~~~~~~~~~~~~~~ | ||
// CHECK:STDERR: fail_todo_compound_access_through_call.carbon:[[@LINE+4]]:3: note: type `.Self` does not implement interface `Core.ImplicitAs(I)` [MissingImplInMemberAccessNote] | ||
// CHECK:STDERR: U.(I.G)().(I.G)(); | ||
// CHECK:STDERR: ^~~~~~~~~~~~~~~ | ||
// CHECK:STDERR: | ||
U.(I.G)().(I.G)(); | ||
} | ||
|
||
// --- fail_todo_compound_access_through_call_with_self_param.carbon | ||
library "[[@TEST_NAME]]"; | ||
|
||
interface I { | ||
let X:! type; | ||
fn G[self: Self]() -> X*; | ||
} | ||
|
||
fn F(U:! I where .X = .Self, v: U) { | ||
// Compound member lookup through a non-type value is possible for methods | ||
// which take a `self` parameter. | ||
|
||
// TODO: This should all work. | ||
|
||
// CHECK:STDERR: fail_todo_compound_access_through_call_with_self_param.carbon:[[@LINE+7]]:15: error: cannot implicitly convert expression of type `.Self*` to `U*` [ConversionFailure] | ||
// CHECK:STDERR: let u: U* = v.(I.G)(); | ||
// CHECK:STDERR: ^~~~~~~~~ | ||
// CHECK:STDERR: fail_todo_compound_access_through_call_with_self_param.carbon:[[@LINE+4]]:15: note: type `.Self*` does not implement interface `Core.ImplicitAs(U*)` [MissingImplInMemberAccessNote] | ||
// CHECK:STDERR: let u: U* = v.(I.G)(); | ||
// CHECK:STDERR: ^~~~~~~~~ | ||
// CHECK:STDERR: | ||
let u: U* = v.(I.G)(); | ||
// `u` is a non-type value. Can call methods with `self` through compound | ||
// member lookup, but can't call methods without `self`. See the | ||
// `compound_access_through_call.carbon` test for the latter. | ||
u->(I.G)(); | ||
|
||
// This is the same as the above, since G() returns a non-type value of type | ||
// `U`. This works because G has a `self` parameter. | ||
v.(I.G)()->(I.G)(); | ||
} | ||
|
||
// --- fail_non_const_associated.carbon | ||
library "[[@TEST_NAME]]"; | ||
|
||
|
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.