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

Permit Coercions in Type Ascriptions #79730

Closed

Conversation

b-naber
Copy link
Contributor

@b-naber b-naber commented Dec 5, 2020

We want to permit coercions of type ascriptions inside coercion sites. To implement this we introduce a TypeAscriptionCtxt, which we pass inside an Expectation down to sub-expressions. Once we encounter a coercion site, we set TypeAscriptionCtxt::Coercion in the Expectation and propagate this down into check_expr_with_expectation. Whenever we encounter a type ascription and TypeAscriptionCtxt::Coercion is set, we coerce the type ascription.

Since not all sites, in which check_expr_coercable_to_type calls originate, are coercion sites (e.g. ExprKind::Assign or some methods in op.rs use check_expr_coercable_to_type), we currently also pass a TypeAscriptionCtxt to check_expr_coercable_to_type. Exposing TypeAscriptionCtxt throughout typeck::check is probably bad, I'm not sure what's the best way to hide the Ctxt, maybe we could call different variants of 'check_expr_coercable_to_type' based on whether the site at which these calls originate is an actual coercion site or not?

Closes #78248

r? @nikomatsakis

@rust-highfive
Copy link
Collaborator

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

If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. Due to the way GitHub handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes.

Please see the contribution instructions for more information.

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Dec 5, 2020
@lcnr lcnr assigned nikomatsakis and unassigned lcnr Dec 5, 2020
Copy link
Contributor

@nikomatsakis nikomatsakis left a comment

Choose a reason for hiding this comment

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

Hey! I left various comments and suggestions -- this is close but not quite there. That said, I had an idea while reviewing for a simpler change that may be preferable which basically sidesteps the motivation for this PR. I pinged on Zulip to see what the lang team thinks about it though (the idea was to forbid type ascription on place expressions, so that x: i32 is just not permitted).

}
}
}

/// When type-checking an expression, we propagate downward
/// whatever type hint we are able in the form of an `Expectation`.
#[derive(Copy, Clone, Debug)]
pub enum Expectation<'tcx> {
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: I feel like we should structure this like

struct Expectation<'tcx> {
    coercion_site: TypeAscriptionCtxt,
    kind: ExpectationKind<'tcx>
}

enum ExpectationKind<"tcx> {
    NoExpectation,
    ....
}

// ExprKind::Type in a sub-expression and TypeAscriptionCtxt is set, we coerce
// the type ascription
#[derive(Copy, Clone, Debug)]
pub enum TypeAscriptionCtxt {
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: Let's rename this to something like CoercionPermitted

expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
ctxt: TypeAscriptionCtxt,
Copy link
Contributor

Choose a reason for hiding this comment

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

It seems like we shouldn't need this argument -- why would you invoke check_expr_coercable_to_type except if you were at a coercion site?

ty::Adt(def, _) if def.is_box() => Expectation::rvalue_hint(self, ty.boxed_ty()),
_ => NoExpectation,
});
let type_ascr_ctxt = expected.get_coercion_ctxt();
Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm, I am not sure we want to propagate the coercion context here.

This applies to box foo expressions, and it says that if you have something like

let x: Box<T> = box bar;

then bar should be coerced to T. This is probably reasonable, but I think we likely want to just say that this is always a coercion site. It doesn't really depend on the context.

@@ -320,7 +341,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let tcx = self.tcx;
let expected_inner = match unop {
hir::UnOp::UnNot | hir::UnOp::UnNeg => expected,
hir::UnOp::UnDeref => NoExpectation,
hir::UnOp::UnDeref => NoExpectation(expected.get_coercion_ctxt()),
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think we want to consider this a coercion site. This corresponds to an expression like *foo, and it doesn't make sense to "coerce" foo to .. anything.

let e_ty = self.check_expr_with_hint(e, coerce_to);
let e_ty = self.check_expr_with_expectation(
e,
ExpectHasType(coerce_to, expected.get_coercion_ctxt()),
Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm, so this is interesting... I think this is another case where we would really want to thread down the CoerceMany instance. What's going on here is that we have something like:

let x: [T] = [a, b, c];

I think that having the check_expr_coercable_to call occur inside check_expr_with_expectation and then calling coerce.coerce may cause a problem. Hmm.

let (element_ty, t) = match uty {
Some(uty) => {
self.check_expr_coercable_to_type(&element, uty, None);
self.check_expr_coercable_to_type(&element, uty, None, type_ascr_ctxt);
Copy link
Contributor

Choose a reason for hiding this comment

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

as above, this argument should not be necessary, but this should always be a coercion site

(uty, uty)
}
None => {
let ty = self.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::MiscVariable,
span: element.span,
});
let element_ty = self.check_expr_has_type_or_error(&element, ty, |_| {});
let element_ty =
self.check_expr_has_type_or_error(&element, ty, |_| {}, type_ascr_ctxt);
Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm, this is a sort of tricky case. This corresponds to [E; 22] and I guess that we want the expression E to always be considered a coercion site. So this should probably just be a call to check_Expr_coerces_to but using the target type of a fresh variable. But I'm not sure why the code is written this way, there may be a reason, I guess it has to do with extracting as much info about the element type as we can. Still, I would prefer to just simplify to always call coercable_To

let elt_ts_iter = elts.iter().enumerate().map(|(i, e)| match flds {
Some(ref fs) if i < fs.len() => {
let ety = fs[i].expect_ty();
self.check_expr_coercable_to_type(&e, ety, None);
self.check_expr_coercable_to_type(&e, ety, None, type_ascr_ctxt);
Copy link
Contributor

Choose a reason for hiding this comment

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

as usual, can remove this parameter

ety
}
_ => self.check_expr_with_expectation(&e, NoExpectation),
_ => self.check_expr_with_expectation(&e, NoExpectation(type_ascr_ctxt)),
Copy link
Contributor

Choose a reason for hiding this comment

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

this should always be considered a coercion site, but we may not have a useful hint

@camelid camelid added A-coercions Area: implicit and explicit `expr as Type` coercions F-type_ascription `#![feature(type_ascription)]` labels Dec 9, 2020
@bors
Copy link
Contributor

bors commented Dec 17, 2020

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

Note that reviewers usually do not review pull requests until merge conflicts are resolved! Once you resolve the conflicts, you should change the labels applied by bors to indicate that your PR is ready for review. Post this as a comment to change the labels:

@rustbot modify labels: +S-waiting-on-review -S-waiting-on-author

@JohnCSimon
Copy link
Member

Ping from triage
@b-naber - can you please resolve the merge conflict, address the comments and alert the reviewer? Thank you!

@JohnCSimon JohnCSimon added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jan 11, 2021
@b-naber
Copy link
Contributor Author

b-naber commented Jan 11, 2021

@JohnCSimon We agreed on trying another approach for this issue (#80788). This PR will be closed if the other PR is accepted.

@Dylan-DPC-zz Dylan-DPC-zz added S-blocked Status: Blocked on something else such as an RFC or other implementation work. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Feb 8, 2021
@nikomatsakis
Copy link
Contributor

Closing in favor of #80788

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-coercions Area: implicit and explicit `expr as Type` coercions F-type_ascription `#![feature(type_ascription)]` S-blocked Status: Blocked on something else such as an RFC or other implementation work.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

permit coercion in type ascription
8 participants