Skip to content

Commit

Permalink
report cyclic class errors
Browse files Browse the repository at this point in the history
Summary: arrange to report on cyclic class definition errors

Differential Revision: D34800222

fbshipit-source-id: e82367158d71571c29206094baa568af26dafc2d
  • Loading branch information
Shayne Fletcher authored and facebook-github-bot committed Mar 10, 2022
1 parent 529e554 commit 65b1c95
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 13 deletions.
2 changes: 1 addition & 1 deletion hphp/hack/src/rupro/lib/folded_decl_provider/fold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -759,6 +759,7 @@ impl<R: Reason> DeclFolder<R> {
&self,
sc: &ShallowClass<R>,
parents: &TypeNameIndexMap<Arc<FoldedClass<R>>>,
mut errors: Vec<TypingError<R>>,
) -> Arc<FoldedClass<R>> {
let inh = Inherited::make(sc, parents);

Expand Down Expand Up @@ -801,7 +802,6 @@ impl<R: Reason> DeclFolder<R> {
.iter()
.for_each(|tc| self.decl_type_const(&mut type_consts, &mut consts, sc, tc));

let mut errors = vec![];
let extends = self.get_extends(sc, parents, &mut errors);
let xhp_attr_deps = self.get_xhp_attr_deps(sc, parents, &mut errors);

Expand Down
34 changes: 22 additions & 12 deletions hphp/hack/src/rupro/lib/folded_decl_provider/provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use crate::decl_defs::{ConstDecl, DeclTy, DeclTy_, FoldedClass, FunDecl, Shallow
use crate::reason::Reason;
use crate::shallow_decl_provider::{self, ShallowDeclProvider};
use crate::special_names::SpecialNames;
use crate::typing_error::{Primary, TypingError};
use oxidized::global_options::GlobalOptions;
use pos::{
ConstName, FunName, MethodName, Positioned, PropName, TypeName, TypeNameIndexMap,
Expand Down Expand Up @@ -133,24 +134,31 @@ impl<R: Reason> LazyFoldedDeclProvider<R> {
fn detect_cycle(
&self,
stack: &mut TypeNameIndexSet,
errors: &mut Vec<TypingError<R>>,
pos_id: &Positioned<TypeName, R::Pos>,
) -> bool {
if stack.contains(&pos_id.id()) {
todo!("TODO(hrust): register error");
errors.push(TypingError::primary(Primary::CyclicClassDef(
pos_id.pos().clone(),
stack.iter().copied().collect(),
)));
true
} else {
false
}
false
}

fn decl_class_type(
&self,
stack: &mut TypeNameIndexSet,
acc: &mut TypeNameIndexMap<Arc<FoldedClass<R>>>,
errors: &mut Vec<TypingError<R>>,
ty: &DeclTy<R>,
) -> Result<()> {
match &**ty.node() {
DeclTy_::DTapply(id_and_args) => {
let pos_id = &id_and_args.0;
if !self.detect_cycle(stack, pos_id) {
if !self.detect_cycle(stack, errors, pos_id) {
if let Some(folded_decl) = self.get_folded_class_impl(stack, pos_id.id())? {
acc.insert(pos_id.id(), folded_decl);
}
Expand Down Expand Up @@ -195,31 +203,32 @@ impl<R: Reason> LazyFoldedDeclProvider<R> {
fn decl_class_parents(
&self,
stack: &mut TypeNameIndexSet,
errors: &mut Vec<TypingError<R>>,
sc: &ShallowClass<R>,
) -> Result<TypeNameIndexMap<Arc<FoldedClass<R>>>> {
let mut acc = Default::default();
for ty in sc.extends.iter() {
self.decl_class_type(stack, &mut acc, ty)
self.decl_class_type(stack, &mut acc, errors, ty)
.map_err(|err| Self::parent_error(sc, ty, err))?;
}
for ty in sc.implements.iter() {
self.decl_class_type(stack, &mut acc, ty)
self.decl_class_type(stack, &mut acc, errors, ty)
.map_err(|err| Self::parent_error(sc, ty, err))?;
}
for ty in sc.uses.iter() {
self.decl_class_type(stack, &mut acc, ty)
self.decl_class_type(stack, &mut acc, errors, ty)
.map_err(|err| Self::parent_error(sc, ty, err))?;
}
for ty in sc.xhp_attr_uses.iter() {
self.decl_class_type(stack, &mut acc, ty)
self.decl_class_type(stack, &mut acc, errors, ty)
.map_err(|err| Self::parent_error(sc, ty, err))?;
}
for ty in sc.req_extends.iter() {
self.decl_class_type(stack, &mut acc, ty)
self.decl_class_type(stack, &mut acc, errors, ty)
.map_err(|err| Self::parent_error(sc, ty, err))?;
}
for ty in sc.req_implements.iter() {
self.decl_class_type(stack, &mut acc, ty)
self.decl_class_type(stack, &mut acc, errors, ty)
.map_err(|err| Self::parent_error(sc, ty, err))?;
}
for ty in sc
Expand All @@ -228,7 +237,7 @@ impl<R: Reason> LazyFoldedDeclProvider<R> {
.map_or([].as_slice(), |et| &et.includes)
.iter()
{
self.decl_class_type(stack, &mut acc, ty)
self.decl_class_type(stack, &mut acc, errors, ty)
.map_err(|err| Self::parent_error(sc, ty, err))?;
}

Expand All @@ -240,15 +249,16 @@ impl<R: Reason> LazyFoldedDeclProvider<R> {
stack: &mut TypeNameIndexSet,
name: TypeName,
) -> Result<Option<Arc<FoldedClass<R>>>> {
let mut errors = vec![];
let shallow_class = match self.shallow_decl_provider.get_class(name)? {
None => return Ok(None),
Some(c) => c,
};
stack.insert(name);
let parents = self.decl_class_parents(stack, &shallow_class)?;
let parents = self.decl_class_parents(stack, &mut errors, &shallow_class)?;
stack.remove(&name);
let folder = DeclFolder::new(Arc::clone(&self.opts), self.special_names);
Ok(Some(folder.decl_class(&shallow_class, &parents)))
Ok(Some(folder.decl_class(&shallow_class, &parents, errors)))
}

fn get_folded_class_impl(
Expand Down
1 change: 1 addition & 0 deletions hphp/hack/src/rupro/lib/typing_error/error_primary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pub enum Primary<R: Reason> {
InvalidTypeHint(R::Pos),
ExpectingTypeHint(R::Pos),
ExpectingReturnTypeHint(R::Pos),
CyclicClassDef(R::Pos, Vec<TypeName>),
TraitReuse {
parent_pos: R::Pos,
parent_name: TypeName,
Expand Down
4 changes: 4 additions & 0 deletions hphp/hack/test/rupro/folded_decls/cyclic_class.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?hh

class A extends C {}
class C extends A {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
FoldedClass {
name: "\\A",
kind: Cclass(
Concrete,
),
substs: {
"\\C": SubstContext {
subst: Subst(
{},
),
class_context: "\\A",
from_req_extends: false,
},
},
ancestors: {
"\\A": A,
"\\C": C,
},
consts: {
"class": ClassConst {
is_synthesized: true,
kind: CCConcrete,
pos: NPos,
ty: HH\classname<this>,
origin: "\\A",
refs: [],
},
},
extends: {
"\\C",
"\\A",
},
}
FoldedClass {
name: "\\C",
kind: Cclass(
Concrete,
),
ancestors: {
"\\A": A,
},
consts: {
"class": ClassConst {
is_synthesized: true,
kind: CCConcrete,
pos: NPos,
ty: HH\classname<this>,
origin: "\\C",
refs: [],
},
},
extends: {
"\\A",
},
decl_errors: [
Primary(
CyclicClassDef(
NPos,
[
"\\A",
"\\C",
],
),
),
],
}

0 comments on commit 65b1c95

Please sign in to comment.