-
Notifications
You must be signed in to change notification settings - Fork 13.4k
WIP: Unstable impls #140399
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
base: master
Are you sure you want to change the base?
WIP: Unstable impls #140399
Conversation
d01f12a
to
9e139e1
Compare
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
486d3d3
to
02f780f
Compare
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
567ec89
to
80fd239
Compare
☔ The latest upstream changes (presumably #142299) made this pull request unmergeable. Please resolve the merge conflicts. |
850e3e1
to
27d9e21
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we stop making TypingMode::PostAnalysis
return Ok(Yes)
when proving ClauseKind::UnstableFeature
, this test will ice: #142368 (comment)
This means the test is working as intended,
I've got nothing technical to add (I've not looked over the code). I just wanted to thank @tiif for taking on this task! It's far from trivial and has been a long-standing desire. |
This comment has been minimized.
This comment has been minimized.
a77d746
to
6e4c902
Compare
This comment has been minimized.
This comment has been minimized.
☔ The latest upstream changes (presumably #142483) made this pull request unmergeable. Please resolve the merge conflicts. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
gg gamer
continue; | ||
|
||
match pred.kind().skip_binder() { | ||
ty::ClauseKind::WellFormed(..) | ty::ClauseKind::UnstableFeature(..) => continue, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ty::ClauseKind::WellFormed(..) | ty::ClauseKind::UnstableFeature(..) => continue, | |
ty::ClauseKind::WellFormed(..) | |
// Unstable feature goals cannot be proven in an empty environment so skip them | |
| ty::ClauseKind::UnstableFeature(..) => continue, |
and then can u move the comment about WellFormed
onto the WellFormed
pattern instead of the whole match
@@ -157,7 +157,8 @@ pub enum AttributeKind { | |||
|
|||
/// Represents `#[allow_internal_unstable]`. | |||
AllowInternalUnstable(ThinVec<(Symbol, Span)>), | |||
|
|||
/// Represents `#[unstable_feature_bound]`. | |||
AllowUnstableFeature(ThinVec<(Symbol, Span)>), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AllowUnstableFeature(ThinVec<(Symbol, Span)>), | |
UnstableFeatureBound(ThinVec<(Symbol, Span)>), |
@@ -24,6 +24,22 @@ impl<S: Stage> CombineAttributeParser<S> for AllowInternalUnstableParser { | |||
} | |||
} | |||
|
|||
pub(crate) struct AllowUnstableFeatureParser; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pub(crate) struct AllowUnstableFeatureParser; | |
pub(crate) struct UnstableFeatureBoundParser; |
@@ -318,6 +319,16 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen | |||
predicates.extend(const_evaluatable_predicates_of(tcx, def_id, &predicates)); | |||
} | |||
|
|||
let attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(def_id)); | |||
let allow_unstable_feature_attr = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let allow_unstable_feature_attr = | |
// FIXME(staged_api): We might want to look at the normal stability attributes too but | |
// first we would need a way to let std/core use APIs with unstable feature bounds from | |
// within stable APIs. | |
let allow_unstable_feature_attr = |
let unstable_feature_stab = | ||
find_attr!(attrs, AttributeKind::AllowUnstableFeature(i) => i) | ||
.map(|i| i.as_slice()) | ||
.unwrap_or_default(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this won't work if there are multiple unstable_feature_bound
attributes. E.g.
#[unstable_feature_bound(feat_foo)]
#[unstable_feature_bound(feat_bar)]
#[unstable(feature = "feat_bar", issue = "none")]
impl Foo for Bar {}
you should be able to do something like:
find_attr!(attrs, AttributeKind::AllowUnstableFeature(i) if i == feature)
to get a yes/no as to whether there's an unstable feature bound on the impl with the same symbol as the stability attr
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This reminds me, I am not sure if I handled multiple attributes case correctly in compiler/rustc_hir_analysis/src/collect/predicates_of.rs
. I will take a look at that too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh, yes, I don't think that's correct either
// For example: | ||
// ``` | ||
// #[unstable_feature_bound(feat_foo)] | ||
// #![unstable(feature = "feat_foo", issue = "none")] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// #![unstable(feature = "feat_foo", issue = "none")] | |
// #[unstable(feature = "feat_foo", issue = "none")] |
@@ -410,6 +409,8 @@ impl<I: Interner> FlagComputation<I> { | |||
self.add_term(t1); | |||
self.add_term(t2); | |||
} | |||
ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(_)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(_)) | |
ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(_sym)) |
to make it a little clearer to readers what the field is that we're ignoring here
/// Allow declaring an impl as unstable. | ||
(internal, impl_stability, "CURRENT_RUSTC_VERSION", None), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// Allow declaring an impl as unstable. | |
(internal, impl_stability, "CURRENT_RUSTC_VERSION", None), |
I think that unstable feature bounds should just live under the staged_api
feature instead of a separate feature gate. Might be a somewhat involved change to go and change everywhere to use staged_api
instead of impl_stability
everywhere :> my bad
if self.cx().features().impl_stability() { | ||
// If we are in std/core, and the feature is not enabled through #[unstable_feature_bound(..)] | ||
return self.evaluate_added_goals_and_make_canonical_response(Certainty::Maybe( | ||
MaybeCause::Ambiguity, | ||
)); | ||
} else { | ||
// Outside of std/core, check if feature is enabled at crate level with #[feature(..)] | ||
// or if we are currently in codegen. | ||
if self.cx().features().enabled(symbol) | ||
|| (self.typing_mode() == TypingMode::PostAnalysis) | ||
{ | ||
return self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes); | ||
} else { | ||
return self.evaluate_added_goals_and_make_canonical_response(Certainty::Maybe( | ||
MaybeCause::Ambiguity, | ||
)); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if self.cx().features().impl_stability() { | |
// If we are in std/core, and the feature is not enabled through #[unstable_feature_bound(..)] | |
return self.evaluate_added_goals_and_make_canonical_response(Certainty::Maybe( | |
MaybeCause::Ambiguity, | |
)); | |
} else { | |
// Outside of std/core, check if feature is enabled at crate level with #[feature(..)] | |
// or if we are currently in codegen. | |
if self.cx().features().enabled(symbol) | |
|| (self.typing_mode() == TypingMode::PostAnalysis) | |
{ | |
return self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes); | |
} else { | |
return self.evaluate_added_goals_and_make_canonical_response(Certainty::Maybe( | |
MaybeCause::Ambiguity, | |
)); | |
} | |
} | |
// During codegen we must assume that all feature bounds hold as we may be | |
// monomorphizing a body from an upstream crate which had an unstable feature | |
// enabled that we do not. | |
// | |
// Note: `feature_bound_holds_in_crate` does not consider a feature to be enabled | |
// if we are in std/core even if there is a corresponding `feature` attribute on the crate. | |
if self.cx().features().feature_bound_holds_in_crate(symbol) | |
|| (self.typing_mode() == TypingMode::PostAnalysis) | |
{ | |
return self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes); | |
} else { | |
return self.evaluate_added_goals_and_make_canonical_response(Certainty::Maybe( | |
MaybeCause::Ambiguity, | |
)); | |
} |
Minor structural change here. Moving the "are we in std/core" check to within the feature_bound_holds_in_crate
method. I think it makes the code a little nicer and also makes the enabled
feature only suitable for use by unstable feature bounds which will prevent people using the API elsewhere.
fn enabled(self, symbol: <TyCtxt<'tcx> as Interner>::Symbol) -> bool { | ||
self.enabled(symbol) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fn enabled(self, symbol: <TyCtxt<'tcx> as Interner>::Symbol) -> bool { | |
self.enabled(symbol) | |
} | |
fn feature_bound_holds_in_crate(self, symbol: <TyCtxt<'tcx> as Interner>::Symbol) -> bool { | |
// We don't consider feature bounds to hold in the crate if we `staged_api` feature is | |
// even when the feature is enabled. This is to prevent accidentally leaking unstable APIs | |
// to stable. | |
!self.staged_api() && self.enabled(symbol) | |
} |
@@ -2274,6 +2277,45 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | |||
} | |||
} | |||
|
|||
fn check_unstable_feature_bound(&self, attr_span: Span, span: Span, target: Target) { | |||
match target { | |||
Target::Fn | Target::Impl => {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Target::Fn | Target::Impl => {} | |
// FIXME(staged_api): There's no reason we can't support more targets here. We're just | |
// being conservative to begin with. | |
Target::Fn | Target::Impl => {} |
r? ghost