Skip to content

Include adjustments to allow unsizing coercions for raw slice pointers in receiver position #82190

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

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
allow unsizing of raw pointers in receiver position
  • Loading branch information
b-naber committed Feb 16, 2021
commit 38d047149be8e0513c4b26fb521fce06ac31934c
23 changes: 21 additions & 2 deletions compiler/rustc_typeck/src/check/method/confirm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::subst::{self, Subst, SubstsRef};
use rustc_middle::ty::{self, GenericParamDefKind, Ty};
use rustc_span::Span;
use rustc_trait_selection::autoderef::Autoderef;
use rustc_trait_selection::traits;

use std::ops::Deref;
Expand Down Expand Up @@ -137,8 +138,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
) -> Ty<'tcx> {
// Commit the autoderefs by calling `autoderef` again, but this
// time writing the results into the various typeck results.
let mut autoderef =
self.autoderef_overloaded_span(self.span, unadjusted_self_ty, self.call_expr.span);
let mut autoderef = self.autoderef_self_ty(unadjusted_self_ty, &pick);
let (_, n) = match autoderef.nth(pick.autoderefs) {
Some(n) => n,
None => {
Expand Down Expand Up @@ -191,6 +191,25 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
target
}

fn autoderef_self_ty(
&'a self,
unadjusted_self_ty: Ty<'tcx>,
pick: &probe::Pick<'tcx>,
) -> Autoderef<'a, 'tcx> {
let autoderef =
self.autoderef_overloaded_span(self.span, unadjusted_self_ty, self.call_expr.span);

// We allow unsize coercions of raw pointers in method callee position
if let &ty::RawPtr(ty::TypeAndMut { ty: t, .. }) = unadjusted_self_ty.kind() {
if let ty::Array(_, _) = t.kind() {
if pick.unsize_raw_ptr() {
return autoderef.include_raw_pointers();
}
}
}
autoderef
}

/// Returns a set of substitutions for the method *receiver* where all type and region
/// parameters are instantiated with fresh variables. This substitution does not include any
/// parameters declared on the method itself.
Expand Down
63 changes: 62 additions & 1 deletion compiler/rustc_typeck/src/check/method/probe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,17 @@ pub struct Pick<'tcx> {
pub unsize: Option<Ty<'tcx>>,
}

impl Pick<'tcx> {
pub(crate) fn unsize_raw_ptr(&self) -> bool {
if let Some(t) = &self.unsize {
if let &ty::Slice(_) = t.kind() {
return self.autoderefs == 1 && self.autoref.is_some();
}
}
false
}
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum PickKind<'tcx> {
InherentImplPick,
Expand Down Expand Up @@ -1062,14 +1073,23 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
fn pick_core(&mut self) -> Option<PickResult<'tcx>> {
let steps = self.steps.clone();

let allow_deref_raw_ptr = |step: &CandidateStep<'tcx>| -> bool {
// allow dereferencing of raw pointers to slices
if let &ty::Slice(_) = step.self_ty.value.value.kind() {
true
} else {
!step.from_unsafe_deref
}
};

// find the first step that works
steps
.iter()
.filter(|step| {
debug!("pick_core: step={:?}", step);
// skip types that are from a type error or that would require dereferencing
// a raw pointer
!step.self_ty.references_error() && !step.from_unsafe_deref
!step.self_ty.references_error() && allow_deref_raw_ptr(&step)
})
.flat_map(|step| {
let InferOk { value: self_ty, obligations: _ } = self
Expand All @@ -1085,6 +1105,10 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
self.pick_by_value_method(step, self_ty).or_else(|| {
self.pick_autorefd_method(step, self_ty, hir::Mutability::Not)
.or_else(|| self.pick_autorefd_method(step, self_ty, hir::Mutability::Mut))
.or_else(|| {
// allow unsizing of raw pointers
self.pick_raw_autorefd_slice_method(step, self_ty)
})
})
})
.next()
Expand Down Expand Up @@ -1701,6 +1725,43 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
self.tcx.associated_items(def_id).in_definition_order().copied().collect()
}
}
fn pick_raw_autorefd_slice_method(
&mut self,
step: &CandidateStep<'tcx>,
self_ty: Ty<'tcx>,
) -> Option<PickResult<'tcx>> {
// To enable raw-ptr unsizing we try to autoref slices to raw pointers
debug!("pick_raw_ptr_autorefd_slice_method(step: {:?}, self_ty: {:?}", step, self_ty);
if let &ty::Slice(_) = self_ty.kind() {
let tcx = self.tcx;

let autoref_ptr_ty =
tcx.mk_ptr(ty::TypeAndMut { ty: self_ty, mutbl: hir::Mutability::Not });
return self
.pick_method(autoref_ptr_ty)
.map(|r| {
r.map(|mut pick| {
pick.autoderefs = step.autoderefs;
pick.autoref = Some(hir::Mutability::Not);
pick.unsize = step.unsize.then_some(self_ty);
pick
})
})
.or_else(|| {
let autoref_mut_ptr_ty =
tcx.mk_ptr(ty::TypeAndMut { ty: self_ty, mutbl: hir::Mutability::Mut });
self.pick_method(autoref_mut_ptr_ty).map(|r| {
r.map(|mut pick| {
pick.autoderefs = step.autoderefs;
pick.autoref = Some(hir::Mutability::Mut);
pick.unsize = step.unsize.then_some(self_ty);
pick
})
})
});
}
None
}
}

impl<'tcx> Candidate<'tcx> {
Expand Down