|
6 | 6 | //! the types in HIR to identify late-bound lifetimes and assign their Debruijn indices. This file |
7 | 7 | //! is also responsible for assigning their semantics to implicit lifetimes in trait objects. |
8 | 8 |
|
| 9 | +use std::assert_matches::assert_matches; |
9 | 10 | use std::cell::RefCell; |
10 | 11 | use std::fmt; |
11 | 12 | use std::ops::ControlFlow; |
@@ -890,12 +891,26 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { |
890 | 891 | fn visit_qpath(&mut self, qpath: &'tcx hir::QPath<'tcx>, id: HirId, _: Span) { |
891 | 892 | match qpath { |
892 | 893 | hir::QPath::Resolved(maybe_qself, path) => { |
| 894 | + // Visit the path before the self type since computing the ambient object lifetime default |
| 895 | + // for the latter requires all lifetime arguments of the trait ref to be already resolved. |
| 896 | + self.visit_path(path, id); |
893 | 897 | if let Some(qself) = maybe_qself { |
894 | | - // FIXME: Actually properly determine the OLD for the self ty! |
895 | | - let scope = Scope::ObjectLifetimeDefault { lifetime: None, s: self.scope }; |
896 | | - self.with(scope, |this| this.visit_ty_unambig(qself)); |
| 898 | + let container = match path.res { |
| 899 | + Res::Def(DefKind::AssocTy, def_id) => Some(( |
| 900 | + self.tcx.parent(def_id), |
| 901 | + &path.segments[..path.segments.len() - 1], |
| 902 | + )), |
| 903 | + _ => None, |
| 904 | + }; |
| 905 | + let object_lifetime_defaults = |
| 906 | + container.map_or(Vec::new(), |(def_id, segs)| self.xyzxx(def_id, segs)); |
| 907 | + if let Some(<) = object_lifetime_defaults.get(0) { |
| 908 | + let scope = Scope::ObjectLifetimeDefault { lifetime: lt, s: self.scope }; |
| 909 | + self.with(scope, |this| this.visit_ty_unambig(qself)); |
| 910 | + } else { |
| 911 | + self.visit_ty_unambig(qself); |
| 912 | + } |
897 | 913 | } |
898 | | - self.visit_path(path, id); |
899 | 914 | } |
900 | 915 | hir::QPath::TypeRelative(qself, segment) => { |
901 | 916 | // Resolving object lifetime defaults for type-relative paths requires type-dependent |
@@ -1058,51 +1073,57 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { |
1058 | 1073 | } |
1059 | 1074 |
|
1060 | 1075 | fn object_lifetime_default(tcx: TyCtxt<'_>, param_def_id: LocalDefId) -> ObjectLifetimeDefault { |
1061 | | - let hir::Node::GenericParam(param) = tcx.hir_node_by_def_id(param_def_id) else { |
1062 | | - bug!("expected GenericParam for object_lifetime_default"); |
| 1076 | + // FIXME: Update comments etc. |
| 1077 | + |
| 1078 | + // Scan the bounds and where-clauses on parameters to extract bounds |
| 1079 | + // of the form `T: 'a` so as to determine the `ObjectLifetimeDefault` |
| 1080 | + // for each type parameter. |
| 1081 | + |
| 1082 | + let (generics, bounds) = match tcx.hir_node_by_def_id(param_def_id) { |
| 1083 | + hir::Node::GenericParam(param) => match param.source { |
| 1084 | + hir::GenericParamSource::Generics => { |
| 1085 | + // FIXME: message |
| 1086 | + assert_matches!(param.kind, GenericParamKind::Type { .. }); |
| 1087 | + (tcx.hir_get_generics(tcx.local_parent(param_def_id)).unwrap(), &[][..]) |
| 1088 | + } |
| 1089 | + hir::GenericParamSource::Binder => return ObjectLifetimeDefault::Empty, |
| 1090 | + }, |
| 1091 | + // For Self ty params |
| 1092 | + hir::Node::Item(&hir::Item { |
| 1093 | + kind: hir::ItemKind::Trait(_, _, _, generics, bounds, _), |
| 1094 | + .. |
| 1095 | + }) => (generics, bounds), |
| 1096 | + _ => bug!("`object_lifetime_default` must only be called on type parameters"), |
1063 | 1097 | }; |
1064 | | - match param.source { |
1065 | | - hir::GenericParamSource::Generics => { |
1066 | | - let parent_def_id = tcx.local_parent(param_def_id); |
1067 | | - let generics = tcx.hir_get_generics(parent_def_id).unwrap(); |
1068 | | - |
1069 | | - // Scan the bounds and where-clauses on parameters to extract bounds |
1070 | | - // of the form `T:'a` so as to determine the `ObjectLifetimeDefault` |
1071 | | - // for each type parameter. |
1072 | | - match param.kind { |
1073 | | - GenericParamKind::Type { .. } => { |
1074 | | - let mut set = Set1::Empty; |
1075 | | - |
1076 | | - // Look for `type: ...` where clauses. |
1077 | | - for bound in generics.bounds_for_param(param_def_id) { |
1078 | | - // Ignore `for<'a> type: ...` as they can change what |
1079 | | - // lifetimes mean (although we could "just" handle it). |
1080 | | - if !bound.bound_generic_params.is_empty() { |
1081 | | - continue; |
1082 | | - } |
1083 | 1098 |
|
1084 | | - for bound in bound.bounds { |
1085 | | - if let hir::GenericBound::Outlives(lifetime) = bound { |
1086 | | - set.insert(lifetime.kind); |
1087 | | - } |
1088 | | - } |
1089 | | - } |
| 1099 | + let mut set = Set1::Empty; |
1090 | 1100 |
|
1091 | | - match set { |
1092 | | - Set1::Empty => ObjectLifetimeDefault::Empty, |
1093 | | - Set1::One(hir::LifetimeKind::Static) => ObjectLifetimeDefault::Static, |
1094 | | - Set1::One(hir::LifetimeKind::Param(param_def_id)) => { |
1095 | | - ObjectLifetimeDefault::Param(param_def_id.to_def_id()) |
1096 | | - } |
1097 | | - _ => ObjectLifetimeDefault::Ambiguous, |
1098 | | - } |
1099 | | - } |
1100 | | - _ => { |
1101 | | - bug!("object_lifetime_default must only be called on a type parameter") |
1102 | | - } |
| 1101 | + let mut add_outlives_bounds = |bounds: &[hir::GenericBound<'_>]| { |
| 1102 | + for bound in bounds { |
| 1103 | + if let hir::GenericBound::Outlives(lifetime) = bound { |
| 1104 | + set.insert(lifetime.res); |
1103 | 1105 | } |
1104 | 1106 | } |
1105 | | - hir::GenericParamSource::Binder => ObjectLifetimeDefault::Empty, |
| 1107 | + }; |
| 1108 | + |
| 1109 | + add_outlives_bounds(bounds); |
| 1110 | + |
| 1111 | + // Look for `Type: ...` where clauses. |
| 1112 | + for bound in generics.bounds_for_param(param_def_id) { |
| 1113 | + // Ignore `for<'a> Type: ...` as they can change what |
| 1114 | + // lifetimes mean (although we could "just" handle it). |
| 1115 | + if !bound.bound_generic_params.is_empty() { |
| 1116 | + add_outlives_bounds(&bound.bounds); |
| 1117 | + } |
| 1118 | + } |
| 1119 | + |
| 1120 | + match set { |
| 1121 | + Set1::Empty => ObjectLifetimeDefault::Empty, |
| 1122 | + Set1::One(hir::LifetimeKind::Static) => ObjectLifetimeDefault::Static, |
| 1123 | + Set1::One(hir::LifetimeKind::Param(param_def_id)) => { |
| 1124 | + ObjectLifetimeDefault::Param(param_def_id.to_def_id()) |
| 1125 | + } |
| 1126 | + _ => ObjectLifetimeDefault::Ambiguous, |
1106 | 1127 | } |
1107 | 1128 | } |
1108 | 1129 |
|
@@ -1683,88 +1704,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { |
1683 | 1704 | // Therefore, we would compute `object_lifetime_defaults` to a |
1684 | 1705 | // vector like `['x, 'static]`. Note that the vector only |
1685 | 1706 | // includes type parameters. |
1686 | | - let object_lifetime_defaults = type_def_id.map_or_else(Vec::new, |def_id| { |
1687 | | - let in_body = { |
1688 | | - let mut scope = self.scope; |
1689 | | - loop { |
1690 | | - match *scope { |
1691 | | - Scope::Root { .. } => break false, |
1692 | | - |
1693 | | - Scope::Body { .. } => break true, |
1694 | | - |
1695 | | - Scope::Binder { s, .. } |
1696 | | - | Scope::ObjectLifetimeDefault { s, .. } |
1697 | | - | Scope::Opaque { s, .. } |
1698 | | - | Scope::Supertrait { s, .. } |
1699 | | - | Scope::TraitRefBoundary { s, .. } |
1700 | | - | Scope::LateBoundary { s, .. } => { |
1701 | | - scope = s; |
1702 | | - } |
1703 | | - } |
1704 | | - } |
1705 | | - }; |
1706 | | - |
1707 | | - let rbv = &self.rbv; |
1708 | | - let generics = self.tcx.generics_of(def_id); |
1709 | | - |
1710 | | - let set_to_region = |set: ObjectLifetimeDefault| match set { |
1711 | | - ObjectLifetimeDefault::Empty => { |
1712 | | - if in_body { |
1713 | | - None |
1714 | | - } else { |
1715 | | - Some(ResolvedArg::StaticLifetime) |
1716 | | - } |
1717 | | - } |
1718 | | - ObjectLifetimeDefault::Static => Some(ResolvedArg::StaticLifetime), |
1719 | | - ObjectLifetimeDefault::Param(param_def_id) => { |
1720 | | - fn param_to_depth_and_index( |
1721 | | - generics: &ty::Generics, |
1722 | | - tcx: TyCtxt<'_>, |
1723 | | - def_id: DefId, |
1724 | | - ) -> (usize, usize) { |
1725 | | - if let Some(&index) = generics.param_def_id_to_index.get(&def_id) { |
1726 | | - let has_self = generics.parent.is_none() && generics.has_self; |
1727 | | - (0, index as usize - generics.parent_count - has_self as usize) |
1728 | | - } else if let Some(parent) = generics.parent { |
1729 | | - let parent = tcx.generics_of(parent); |
1730 | | - let (index, depth) = param_to_depth_and_index(parent, tcx, def_id); |
1731 | | - (depth + 1, index) |
1732 | | - } else { |
1733 | | - unreachable!() |
1734 | | - } |
1735 | | - } |
1736 | | - |
1737 | | - let (depth, index) = param_to_depth_and_index(generics, self.tcx, param_def_id); |
1738 | | - path.segments[path.segments.len() - depth - 1] |
1739 | | - .args |
1740 | | - .and_then(|args| args.args.get(index)) |
1741 | | - .and_then(|arg| match arg { |
1742 | | - GenericArg::Lifetime(lt) => rbv.defs.get(<.hir_id.local_id).copied(), |
1743 | | - _ => None, |
1744 | | - }) |
1745 | | - } |
1746 | | - ObjectLifetimeDefault::Ambiguous => None, |
1747 | | - }; |
1748 | | - generics |
1749 | | - .own_params |
1750 | | - .iter() |
1751 | | - .filter_map(|param| { |
1752 | | - match self.tcx.def_kind(param.def_id) { |
1753 | | - // Generic consts don't impose any constraints. |
1754 | | - // |
1755 | | - // We still store a dummy value here to allow generic parameters |
1756 | | - // in an arbitrary order. |
1757 | | - DefKind::ConstParam => Some(ObjectLifetimeDefault::Empty), |
1758 | | - DefKind::TyParam => Some(self.tcx.object_lifetime_default(param.def_id)), |
1759 | | - // We may also get a `Trait` or `TraitAlias` because of how generics `Self` parameter |
1760 | | - // works. Ignore it because it can't have a meaningful lifetime default. |
1761 | | - DefKind::LifetimeParam | DefKind::Trait | DefKind::TraitAlias => None, |
1762 | | - dk => bug!("unexpected def_kind {:?}", dk), |
1763 | | - } |
1764 | | - }) |
1765 | | - .map(set_to_region) |
1766 | | - .collect() |
1767 | | - }); |
| 1707 | + let object_lifetime_defaults = |
| 1708 | + type_def_id.map_or_else(Vec::new, |def_id| self.xyzxx(def_id, &path.segments)); |
1768 | 1709 |
|
1769 | 1710 | debug!(?object_lifetime_defaults); |
1770 | 1711 |
|
@@ -1899,6 +1840,88 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { |
1899 | 1840 | } |
1900 | 1841 | } |
1901 | 1842 |
|
| 1843 | + fn xyzxx(&self, def_id: DefId, segments: &[hir::PathSegment<'_>]) -> Vec<Option<ResolvedArg>> { |
| 1844 | + let in_body = { |
| 1845 | + let mut scope = self.scope; |
| 1846 | + loop { |
| 1847 | + match *scope { |
| 1848 | + Scope::Root { .. } => break false, |
| 1849 | + |
| 1850 | + Scope::Body { .. } => break true, |
| 1851 | + |
| 1852 | + Scope::Binder { s, .. } |
| 1853 | + | Scope::ObjectLifetimeDefault { s, .. } |
| 1854 | + | Scope::Opaque { s, .. } |
| 1855 | + | Scope::Supertrait { s, .. } |
| 1856 | + | Scope::TraitRefBoundary { s, .. } |
| 1857 | + | Scope::LateBoundary { s, .. } => { |
| 1858 | + scope = s; |
| 1859 | + } |
| 1860 | + } |
| 1861 | + } |
| 1862 | + }; |
| 1863 | + |
| 1864 | + let generics = self.tcx.generics_of(def_id); |
| 1865 | + |
| 1866 | + let set_to_region = |set: ObjectLifetimeDefault| match set { |
| 1867 | + ObjectLifetimeDefault::Empty => { |
| 1868 | + if in_body { |
| 1869 | + None |
| 1870 | + } else { |
| 1871 | + Some(ResolvedArg::StaticLifetime) |
| 1872 | + } |
| 1873 | + } |
| 1874 | + ObjectLifetimeDefault::Static => Some(ResolvedArg::StaticLifetime), |
| 1875 | + ObjectLifetimeDefault::Param(param_def_id) => { |
| 1876 | + fn param_to_depth_and_index( |
| 1877 | + generics: &ty::Generics, |
| 1878 | + tcx: TyCtxt<'_>, |
| 1879 | + def_id: DefId, |
| 1880 | + ) -> (usize, usize) { |
| 1881 | + if let Some(&index) = generics.param_def_id_to_index.get(&def_id) { |
| 1882 | + let has_self = generics.parent.is_none() && generics.has_self; |
| 1883 | + (0, index as usize - generics.parent_count - has_self as usize) |
| 1884 | + } else if let Some(parent) = generics.parent { |
| 1885 | + let parent = tcx.generics_of(parent); |
| 1886 | + let (index, depth) = param_to_depth_and_index(parent, tcx, def_id); |
| 1887 | + (depth + 1, index) |
| 1888 | + } else { |
| 1889 | + unreachable!() |
| 1890 | + } |
| 1891 | + } |
| 1892 | + |
| 1893 | + let (depth, index) = param_to_depth_and_index(generics, self.tcx, param_def_id); |
| 1894 | + segments[segments.len() - depth - 1] |
| 1895 | + .args |
| 1896 | + .and_then(|args| args.args.get(index)) |
| 1897 | + .and_then(|arg| match arg { |
| 1898 | + GenericArg::Lifetime(lt) => self.rbv.defs.get(<.hir_id.local_id).copied(), |
| 1899 | + _ => None, |
| 1900 | + }) |
| 1901 | + } |
| 1902 | + ObjectLifetimeDefault::Ambiguous => None, |
| 1903 | + }; |
| 1904 | + generics |
| 1905 | + .own_params |
| 1906 | + .iter() |
| 1907 | + .filter_map(|param| { |
| 1908 | + match self.tcx.def_kind(param.def_id) { |
| 1909 | + // Generic consts don't impose any constraints. |
| 1910 | + // |
| 1911 | + // We still store a dummy value here to allow generic parameters |
| 1912 | + // in an arbitrary order. |
| 1913 | + DefKind::ConstParam => Some(ObjectLifetimeDefault::Empty), |
| 1914 | + DefKind::TyParam | DefKind::Trait => { |
| 1915 | + Some(self.tcx.object_lifetime_default(param.def_id)) |
| 1916 | + } |
| 1917 | + DefKind::LifetimeParam | DefKind::TraitAlias => None, |
| 1918 | + dk => bug!("unexpected def_kind {:?}", dk), |
| 1919 | + } |
| 1920 | + }) |
| 1921 | + .map(set_to_region) |
| 1922 | + .collect() |
| 1923 | + } |
| 1924 | + |
1902 | 1925 | /// Returns all the late-bound vars that come into scope from supertrait HRTBs, based on the |
1903 | 1926 | /// associated type name and starting trait. |
1904 | 1927 | /// For example, imagine we have |
|
0 commit comments