Skip to content

Commit

Permalink
Rollup merge of #105897 - oli-obk:tait_patterns, r=TaKO8Ki
Browse files Browse the repository at this point in the history
Fix an opaque type ICE

fixes #104551

The issue is that if you have

```rust
type T = impl Sized;
let (_a, _b): T = ..
```

we have only the type annotation `T`, but want to use that ascription for `_a` and `_b`, so what we generate is a type ascription plus a field projection saying `_a`'s type is `T::0`. Of course `T` has no fields. Of course we could also not generate type annotations for projections into opaque types at all, but that's more fragile, as we now have to make sure that https://github.com/rust-lang/rust/blob/12bbdbdb440119a0b86d2ee742ec1460cdb2c5b9/compiler/rustc_mir_build/src/build/matches/mod.rs#L709 doesn't have any arm that introduces a user type annotation except for `PatKind::Binding`.
  • Loading branch information
matthiaskrgr authored Dec 20, 2022
2 parents 4726e51 + c9588d5 commit a4ef47d
Show file tree
Hide file tree
Showing 7 changed files with 69 additions and 35 deletions.
24 changes: 21 additions & 3 deletions compiler/rustc_borrowck/src/diagnostics/region_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ use rustc_infer::infer::{
use rustc_middle::hir::place::PlaceBase;
use rustc_middle::mir::{ConstraintCategory, ReturnConstraint};
use rustc_middle::ty::subst::InternalSubsts;
use rustc_middle::ty::Region;
use rustc_middle::ty::TypeVisitor;
use rustc_middle::ty::{self, RegionVid, Ty};
use rustc_middle::ty::{Region, TyCtxt};
use rustc_span::symbol::{kw, Ident};
use rustc_span::Span;
use rustc_span::{Span, DUMMY_SP};

use crate::borrowck_errors;
use crate::session_diagnostics::{
Expand Down Expand Up @@ -70,7 +70,25 @@ impl<'tcx> ConstraintDescription for ConstraintCategory<'tcx> {
///
/// Usually we expect this to either be empty or contain a small number of items, so we can avoid
/// allocation most of the time.
pub(crate) type RegionErrors<'tcx> = Vec<RegionErrorKind<'tcx>>;
pub(crate) struct RegionErrors<'tcx>(Vec<RegionErrorKind<'tcx>>, TyCtxt<'tcx>);

impl<'tcx> RegionErrors<'tcx> {
pub fn new(tcx: TyCtxt<'tcx>) -> Self {
Self(vec![], tcx)
}
#[track_caller]
pub fn push(&mut self, val: impl Into<RegionErrorKind<'tcx>>) {
let val = val.into();
self.1.sess.delay_span_bug(DUMMY_SP, "{val:?}");
self.0.push(val);
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn into_iter(self) -> impl Iterator<Item = RegionErrorKind<'tcx>> {
self.0.into_iter()
}
}

#[derive(Clone, Debug)]
pub(crate) enum RegionErrorKind<'tcx> {
Expand Down
43 changes: 23 additions & 20 deletions compiler/rustc_borrowck/src/region_infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -562,7 +562,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
let mir_def_id = body.source.def_id();
self.propagate_constraints(body);

let mut errors_buffer = RegionErrors::new();
let mut errors_buffer = RegionErrors::new(infcx.tcx);

// If this is a closure, we can propagate unsatisfied
// `outlives_requirements` to our creator, so create a vector
Expand Down Expand Up @@ -1647,26 +1647,29 @@ impl<'tcx> RegionInferenceContext<'tcx> {
let longer_fr_scc = self.constraint_sccs.scc(longer_fr);
debug!("check_bound_universal_region: longer_fr_scc={:?}", longer_fr_scc,);

// If we have some bound universal region `'a`, then the only
// elements it can contain is itself -- we don't know anything
// else about it!
let Some(error_element) = ({
self.scc_values.elements_contained_in(longer_fr_scc).find(|element| match element {
RegionElement::Location(_) => true,
RegionElement::RootUniversalRegion(_) => true,
RegionElement::PlaceholderRegion(placeholder1) => placeholder != *placeholder1,
})
}) else {
return;
};
debug!("check_bound_universal_region: error_element = {:?}", error_element);
for error_element in self.scc_values.elements_contained_in(longer_fr_scc) {
match error_element {
RegionElement::Location(_) | RegionElement::RootUniversalRegion(_) => {}
// If we have some bound universal region `'a`, then the only
// elements it can contain is itself -- we don't know anything
// else about it!
RegionElement::PlaceholderRegion(placeholder1) => {
if placeholder == placeholder1 {
continue;
}
}
}

// Find the region that introduced this `error_element`.
errors_buffer.push(RegionErrorKind::BoundUniversalRegionError {
longer_fr,
error_element,
placeholder,
});
errors_buffer.push(RegionErrorKind::BoundUniversalRegionError {
longer_fr,
error_element,
placeholder,
});

// Stop after the first error, it gets too noisy otherwise, and does not provide more information.
break;
}
debug!("check_bound_universal_region: all bounds satisfied");
}

#[instrument(level = "debug", skip(self, infcx, errors_buffer))]
Expand Down
14 changes: 9 additions & 5 deletions compiler/rustc_borrowck/src/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1153,27 +1153,31 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
category: ConstraintCategory<'tcx>,
) -> Fallible<()> {
let annotated_type = self.user_type_annotations[user_ty.base].inferred_ty;
trace!(?annotated_type);
let mut curr_projected_ty = PlaceTy::from_ty(annotated_type);

let tcx = self.infcx.tcx;

for proj in &user_ty.projs {
if let ty::Alias(ty::Opaque, ..) = curr_projected_ty.ty.kind() {
// There is nothing that we can compare here if we go through an opaque type.
// We're always in its defining scope as we can otherwise not project through
// it, so we're constraining it anyways.
return Ok(());
}
let projected_ty = curr_projected_ty.projection_ty_core(
tcx,
self.param_env,
proj,
|this, field, _| {
|this, field, ()| {
let ty = this.field_ty(tcx, field);
self.normalize(ty, locations)
},
|_, _| unreachable!(),
);
curr_projected_ty = projected_ty;
}
debug!(
"user_ty base: {:?} freshened: {:?} projs: {:?} yields: {:?}",
user_ty.base, annotated_type, user_ty.projs, curr_projected_ty
);
trace!(?curr_projected_ty);

let ty = curr_projected_ty.ty;
self.relate_types(ty, v.xform(ty::Variance::Contravariant), a, locations, category)?;
Expand Down
7 changes: 3 additions & 4 deletions compiler/rustc_middle/src/mir/tcx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,9 @@ impl<'tcx> PlaceTy<'tcx> {
/// not carry a `Ty` for `T`.)
///
/// Note that the resulting type has not been normalized.
#[instrument(level = "debug", skip(tcx), ret)]
pub fn field_ty(self, tcx: TyCtxt<'tcx>, f: Field) -> Ty<'tcx> {
let answer = match self.ty.kind() {
match self.ty.kind() {
ty::Adt(adt_def, substs) => {
let variant_def = match self.variant_index {
None => adt_def.non_enum_variant(),
Expand All @@ -47,9 +48,7 @@ impl<'tcx> PlaceTy<'tcx> {
}
ty::Tuple(tys) => tys[f.index()],
_ => bug!("extracting field of non-tuple non-adt: {:?}", self),
};
debug!("field_ty self: {:?} f: {:?} yields: {:?}", self, f, answer);
answer
}
}

/// Convenience wrapper around `projection_ty_core` for
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_mir_build/src/build/expr/as_constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,14 @@ pub fn as_constant_inner<'tcx>(

let literal = ConstantKind::Val(ConstValue::Scalar(Scalar::Int(lit)), ty);

Constant { span, user_ty: user_ty, literal }
Constant { span, user_ty, literal }
}
ExprKind::ZstLiteral { ref user_ty } => {
let user_ty = user_ty.as_ref().map(push_cuta).flatten();

let literal = ConstantKind::Val(ConstValue::ZeroSized, ty);

Constant { span, user_ty: user_ty, literal }
Constant { span, user_ty, literal }
}
ExprKind::NamedConst { def_id, substs, ref user_ty } => {
let user_ty = user_ty.as_ref().map(push_cuta).flatten();
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_mir_build/src/build/matches/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2210,7 +2210,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
BindingMode::ByValue => ty::BindingMode::BindByValue(mutability),
BindingMode::ByRef(_) => ty::BindingMode::BindByReference(mutability),
};
let local = LocalDecl::<'tcx> {
let local = LocalDecl {
mutability,
ty: var_ty,
user_ty: if user_ty.is_empty() { None } else { Some(Box::new(user_ty)) },
Expand Down
10 changes: 10 additions & 0 deletions src/test/ui/type-alias-impl-trait/destructuring.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#![feature(type_alias_impl_trait)]

// check-pass

// issue: https://github.com/rust-lang/rust/issues/104551

fn main() {
type T = impl Sized;
let (_a, _b): T = (1u32, 2u32);
}

0 comments on commit a4ef47d

Please sign in to comment.