Skip to content
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

Require TAITs to appear in the signature of items that register a hidden type #107809

Conversation

oli-obk
Copy link
Contributor

@oli-obk oli-obk commented Feb 8, 2023

fixes #107645

We now error in case an opaque type gets constrained in a function/item that doesn't have the opaque type in its return type or argument types (Option 5 of #107645):

Any item in the defining scope can register hidden types, but we error out if the TAIT is not in the return type or argument types (post normalization, see below).
We still look at all functions in the defining scope, there's no change in cycle errors.

This is forward compatible to all other designs.

We normalize the argument types and return type before checking for opaque types in order to allow cases like

impl Iterator for Foo {
    type Item = impl Debug;
    fn next(&mut self) -> Option<Self::Item> {
        ...
    }
}

This means if you have a -> <TAIT as Trait>::AssocType that is not a constraining use and will error for now. We can later check both pre and post-normalization to allow that, too. The current design is entirely forward compatible with it.

@rustbot
Copy link
Collaborator

rustbot commented Feb 8, 2023

Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @cjgillot (or someone else) soon.

Please see the contribution instructions for more information.

@rustbot rustbot added A-translation Area: Translation infrastructure, and migrating existing diagnostics to SessionDiagnostic S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Feb 8, 2023
@rustbot
Copy link
Collaborator

rustbot commented Feb 8, 2023

rustc_error_messages was changed

cc @davidtwco, @compiler-errors, @JohnTitor, @TaKO8Ki

Some changes occurred in src/tools/clippy

cc @rust-lang/clippy

@jackh726
Copy link
Member

Can you talk a bit about what's different between this and #107073?

@oli-obk
Copy link
Contributor Author

oli-obk commented Feb 10, 2023

the difference is a bit subtle, but basically this PR avoids any risk of having to do backwards incompatible changes later, as it is forwards compatible with the other PR. So we can in the future decide to go with a more permissive implementation.

The guarantees for IDEs are the same, they don't need to look at any items that don't have the TAIT in its signature.

@bors
Copy link
Contributor

bors commented Feb 10, 2023

☔ The latest upstream changes (presumably #107652) made this pull request unmergeable. Please resolve the merge conflicts.

@pnkfelix
Copy link
Member

@oli-obk can you put a precise writeup of the semantics for the lang team to review, either on this PR, or as a comment/description-edit on #107645 ?

In particular, "we then error out if they did end up registering a hidden type but didn't have the TAIT in their signature" is open to interpretation about whether the where clauses of a function are part of its signature or not. (At least, I know Niko has sometimes considered the where-clauses to have a somewhat less significant role compared to e.g. the types of the formal parameters or return type.)

@oli-obk
Copy link
Contributor Author

oli-obk commented Feb 16, 2023

I updated #107645 (which already explicitly mentioned where bounds, but I made the non-where bound option its own option)

@oli-obk oli-obk force-pushed the reject_tait_defining_scopes_unless_in_sig branch from 7798e7c to 8552b71 Compare March 7, 2023 07:49
@rustbot
Copy link
Collaborator

rustbot commented Mar 7, 2023

These commits modify the Cargo.lock file. Random changes to Cargo.lock can be introduced when switching branches and rebasing PRs.
This was probably unintentional and should be reverted before this PR is merged.

If this was intentional then you can ignore this comment.

@oli-obk oli-obk force-pushed the reject_tait_defining_scopes_unless_in_sig branch 2 times, most recently from ec0331c to c83b23d Compare March 7, 2023 08:29
Copy link
Contributor

@cjgillot cjgillot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the (very) slow review @oli-obk. I don't have much to say, mostly a few questions about tests.

return true;
}

if tcx.is_closure(def_id.to_def_id()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this only apply for closures, or also for inline consts? IOW, should we check is_typeck_child here?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a test for the ban on closure signatures? I saw tests/ui/type-alias-impl-trait/issue-63263-closure-return.rs is changed to accommodate it, but I missed the "fail" test.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right on all accounts. There were no tests, and there were especially none for inline consts. I added them and fixed it so that inline consts actually work at all.

// In case we are inferring the return signature (via `_` types), ignore defining use
// rules, as we'll error out anyway. This helps improve diagnostics, which otherwise
// may just see `ty::Error` instead of `ty::Alias(Opaque, _)` and not produce better errors.
if fn_sig_infer { DefiningAnchor::Bubble } else { DefiningAnchor::Bind(def_id) }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which are the diagnostics changed by this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An example is

type Pointer<T> = impl std::ops::Deref<Target=T>;

fn test() -> Pointer<_> {
    //~^ ERROR: the placeholder `_` is not allowed within types
    Box::new(1)
}

which produces the following error:

error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
  --> $DIR/issue-77179.rs:7:22
   |
LL | fn test() -> Pointer<_> {
   |              --------^-
   |              |       |
   |              |       not allowed in type signatures
   |              help: replace with the correct return type: `Pointer<i32>`

but without the change it would not see Pointer<i32> but just TyKind::Error and thus not report any suggestion, even if the main error would still be emitted

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isn't using Pointer<i32> forbidden here anyways, it currently results in the following (bad) error: playground

error[E0792]: expected generic type parameter, found `i32`
 --> src/lib.rs:5:5
  |
2 | type Pointer<T> = impl std::ops::Deref<Target = T>;
  |              - this generic parameter must be used with a generic type parameter
...
5 |     Box::new(1)
  |     ^^^^^^^^^^^

i personally feel like this is not worth it as it imo makes the code noticeably more confusing for a fairly small benefit.

@oli-obk oli-obk force-pushed the reject_tait_defining_scopes_unless_in_sig branch from 9119da8 to b465336 Compare March 14, 2023 09:47
@bors
Copy link
Contributor

bors commented Mar 14, 2023

☔ The latest upstream changes (presumably #104833) made this pull request unmergeable. Please resolve the merge conflicts.

@oli-obk oli-obk force-pushed the reject_tait_defining_scopes_unless_in_sig branch from b465336 to 375dfa4 Compare March 14, 2023 15:09
@rust-log-analyzer

This comment has been minimized.

@oli-obk oli-obk force-pushed the reject_tait_defining_scopes_unless_in_sig branch from 4c4d729 to 733e444 Compare March 15, 2023 11:57
Copy link
Contributor

@lcnr lcnr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

by looking into adts you can probably get an infinite loop if you have the following type in the signature

struct Foo<T: 'static> {
    field: &'static Foo<(T,)>,
    other_field: T,
}

tcx: self.tcx,
ct_op: |c| c,
ty_op: |t| t,
lt_op: |_| self.tcx.lifetimes.re_erased,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't erase bound regions here, only escaping bound regions 🤔

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you could implement fn fold_binder to call https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TyCtxt.html#method.replace_bound_vars_uncached, replacing bound vars with self.tcx.lifetime.re_erased and eagerly replace all free regions that way

}
// Types that have opaque type fields must get walked manually, they
// would not be seen by the type visitor otherwise.
ty::Adt(adt_def, substs) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so the type can be contained in an Adt? please add that to the PR description.

also, this can be adt_def.all_fields instead of the variants -> fields nested loop

// In case we are inferring the return signature (via `_` types), ignore defining use
// rules, as we'll error out anyway. This helps improve diagnostics, which otherwise
// may just see `ty::Error` instead of `ty::Alias(Opaque, _)` and not produce better errors.
if fn_sig_infer { DefiningAnchor::Bubble } else { DefiningAnchor::Bind(def_id) }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isn't using Pointer<i32> forbidden here anyways, it currently results in the following (bad) error: playground

error[E0792]: expected generic type parameter, found `i32`
 --> src/lib.rs:5:5
  |
2 | type Pointer<T> = impl std::ops::Deref<Target = T>;
  |              - this generic parameter must be used with a generic type parameter
...
5 |     Box::new(1)
  |     ^^^^^^^^^^^

i personally feel like this is not worth it as it imo makes the code noticeably more confusing for a fairly small benefit.

@oli-obk
Copy link
Contributor Author

oli-obk commented Apr 6, 2023

Closing in favor of #110010

@oli-obk oli-obk closed this Apr 6, 2023
@oli-obk oli-obk deleted the reject_tait_defining_scopes_unless_in_sig branch May 30, 2023 10:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-translation Area: Translation infrastructure, and migrating existing diagnostics to SessionDiagnostic S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

TAIT defining scope options
8 participants